diff --git a/clover.xml b/clover.xml index 05f71659..2bb0e8c8 100644 --- a/clover.xml +++ b/clover.xml @@ -1,6 +1,6 @@ - - + + @@ -8,17 +8,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -37,42 +37,42 @@ - - - + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -87,8 +87,8 @@ - - + + @@ -106,9 +106,9 @@ - - - + + + @@ -118,7 +118,7 @@ - + @@ -126,43 +126,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -185,8 +214,8 @@ - - + + @@ -210,19 +239,19 @@ - - - + + + - - + + - + @@ -234,17 +263,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -277,14 +306,14 @@ - - - - - - - - + + + + + + + + @@ -311,9 +340,9 @@ - - - + + + @@ -326,8 +355,8 @@ - - + + @@ -341,158 +370,158 @@ - - - + + + - - + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - + + + + + + - - + + - - - - - - - - - - - + + + + + + + + + + + - + - - - - - - - + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - + @@ -502,12 +531,12 @@ - - + + - - + + @@ -522,9 +551,9 @@ - - - + + + @@ -537,866 +566,878 @@ - - + + - - + + - - - - - + + + + + - - + + - - + + - - + + - + - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + @@ -1442,6 +1483,6 @@ - + diff --git a/src/Schema/Attribute/AbstractAttributeItem.php b/src/Schema/Attribute/AbstractAttributeItem.php index 98a7fd47..ce75a25a 100644 --- a/src/Schema/Attribute/AbstractAttributeItem.php +++ b/src/Schema/Attribute/AbstractAttributeItem.php @@ -4,10 +4,13 @@ namespace GoetasWebservices\XML\XSDReader\Schema\Attribute; +use GoetasWebservices\XML\XSDReader\Schema\CustomAttributeContainerTrait; use GoetasWebservices\XML\XSDReader\Schema\Item; abstract class AbstractAttributeItem extends Item implements AttributeSingle { + use CustomAttributeContainerTrait; + protected ?string $fixed = null; protected ?string $default = null; diff --git a/src/Schema/Attribute/AttributeSingle.php b/src/Schema/Attribute/AttributeSingle.php index 4f7114fa..e90449b5 100644 --- a/src/Schema/Attribute/AttributeSingle.php +++ b/src/Schema/Attribute/AttributeSingle.php @@ -4,9 +4,10 @@ namespace GoetasWebservices\XML\XSDReader\Schema\Attribute; +use GoetasWebservices\XML\XSDReader\Schema\CustomAttributeContainerInterface; use GoetasWebservices\XML\XSDReader\Schema\Type\Type; -interface AttributeSingle extends AttributeItem +interface AttributeSingle extends AttributeItem, CustomAttributeContainerInterface { public const USE_OPTIONAL = 'optional'; diff --git a/src/Schema/CustomAttribute.php b/src/Schema/CustomAttribute.php new file mode 100644 index 00000000..b04833fb --- /dev/null +++ b/src/Schema/CustomAttribute.php @@ -0,0 +1,45 @@ + + */ +class CustomAttribute +{ + private string $namespaceURI; + + private string $name; + + private string $value; + + public function __construct( + string $namespaceURI, + string $name, + string $value + ) { + $this->namespaceURI = $namespaceURI; + $this->name = $name; + $this->value = $value; + } + + public function getNamespaceURI(): string + { + return $this->namespaceURI; + } + + public function getName(): string + { + return $this->name; + } + + public function getValue(): string + { + return $this->value; + } +} diff --git a/src/Schema/CustomAttributeContainerInterface.php b/src/Schema/CustomAttributeContainerInterface.php new file mode 100644 index 00000000..a62e3290 --- /dev/null +++ b/src/Schema/CustomAttributeContainerInterface.php @@ -0,0 +1,18 @@ + $customAttributes + */ + public function setCustomAttributes(array $customAttributes): void; + + /** + * @return list + */ + public function getCustomAttributes(): array; +} diff --git a/src/Schema/CustomAttributeContainerTrait.php b/src/Schema/CustomAttributeContainerTrait.php new file mode 100644 index 00000000..6df52e5e --- /dev/null +++ b/src/Schema/CustomAttributeContainerTrait.php @@ -0,0 +1,29 @@ + + */ + protected array $customAttributes = []; + + /** + * @return list + */ + public function getCustomAttributes(): array + { + return $this->customAttributes; + } + + /** + * @param list $customAttributes + */ + public function setCustomAttributes(array $customAttributes): void + { + $this->customAttributes = $customAttributes; + } +} diff --git a/src/Schema/Element/AbstractElementSingle.php b/src/Schema/Element/AbstractElementSingle.php index f933d3f5..63646adb 100644 --- a/src/Schema/Element/AbstractElementSingle.php +++ b/src/Schema/Element/AbstractElementSingle.php @@ -4,10 +4,13 @@ namespace GoetasWebservices\XML\XSDReader\Schema\Element; +use GoetasWebservices\XML\XSDReader\Schema\CustomAttributeContainerTrait; use GoetasWebservices\XML\XSDReader\Schema\Item; class AbstractElementSingle extends Item implements ElementSingle, InterfaceSetAbstract { + use CustomAttributeContainerTrait; + protected int $min = 1; protected int $max = 1; diff --git a/src/Schema/Element/ElementSingle.php b/src/Schema/Element/ElementSingle.php index 3fd1bf6e..9c0066e0 100644 --- a/src/Schema/Element/ElementSingle.php +++ b/src/Schema/Element/ElementSingle.php @@ -4,9 +4,10 @@ namespace GoetasWebservices\XML\XSDReader\Schema\Element; +use GoetasWebservices\XML\XSDReader\Schema\CustomAttributeContainerInterface; use GoetasWebservices\XML\XSDReader\Schema\Type\Type; -interface ElementSingle extends ElementItem, InterfaceSetMinMax, InterfaceSetFixed, InterfaceSetDefault +interface ElementSingle extends ElementItem, InterfaceSetMinMax, InterfaceSetFixed, InterfaceSetDefault, CustomAttributeContainerInterface { public function getType(): ?Type; diff --git a/src/SchemaReader.php b/src/SchemaReader.php index 9cf259ae..8642865f 100644 --- a/src/SchemaReader.php +++ b/src/SchemaReader.php @@ -15,6 +15,7 @@ use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeRef; use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeSingle; use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group as AttributeGroup; +use GoetasWebservices\XML\XSDReader\Schema\CustomAttribute; use GoetasWebservices\XML\XSDReader\Schema\Element\AbstractElementSingle; use GoetasWebservices\XML\XSDReader\Schema\Element\Choice; use GoetasWebservices\XML\XSDReader\Schema\Element\Element; @@ -236,6 +237,27 @@ private function fillAttribute(AttributeSingle $attribute, \DOMElement $node): v if ($node->hasAttribute('use')) { $attribute->setUse($node->getAttribute('use')); } + + $attribute->setCustomAttributes($this->loadCustomAttributesForElement($attribute, $node)); + } + + /** + * @return list + */ + private function loadCustomAttributesForElement(SchemaItem $item, \DOMElement $node): array + { + $customAttributes = []; + foreach ($node->attributes as $attr) { + if (null !== $attr->namespaceURI && self::XSD_NS !== $attr->namespaceURI) { + $customAttributes[] = new CustomAttribute( + $attr->namespaceURI, + $attr->name, + $attr->value + ); + } + } + + return $customAttributes; } private function loadAttributeOrElementDef( @@ -1456,6 +1478,8 @@ private function fillElement(AbstractElementSingle $element, \DOMElement $node): $element->setLocal(true); } } + + $element->setCustomAttributes($this->loadCustomAttributesForElement($element, $node)); } private function addAttributeFromAttributeOrRef( diff --git a/tests/AttributesTest.php b/tests/AttributesTest.php index ec1ec380..90ab0f3f 100644 --- a/tests/AttributesTest.php +++ b/tests/AttributesTest.php @@ -144,4 +144,82 @@ public function testAttributeUseOverriding(): void self::assertEquals('language', $attribute->getType()->getName()); self::assertEquals(AttributeSingle::USE_REQUIRED, $attribute->getUse()); } + + public function testCustomAttributesInformation(): void + { + $schema = $this->reader->readString( + ' + + + ' + ); + + $myAttribute = $schema->findAttribute('myAttribute', 'http://www.example.com'); + self::assertInstanceOf(AttributeDef::class, $myAttribute); + + $customAttributes = $myAttribute->getCustomAttributes(); + self::assertCount(1, $customAttributes); + self::assertEquals('customAttributes', $customAttributes[0]->getName()); + self::assertEquals('hello', $customAttributes[0]->getValue()); + self::assertEquals('http://www.example.com', $customAttributes[0]->getNamespaceURI()); + } + + public function testExternalSchemaReferencingCustomAttributesInformationPrefixed(): void + { + $dom = new \DOMDocument(); + $dom->loadXML( + ' + + + + + + + + + + '); + $schema = $this->reader->readNodes(iterator_to_array($dom->documentElement->childNodes), 'file.xsd'); + + $myAttribute = $schema->findAttribute('myAttribute', 'http://www.example.com'); + self::assertInstanceOf(AttributeDef::class, $myAttribute); + + $customAttributes = $myAttribute->getCustomAttributes(); + self::assertCount(1, $customAttributes); + self::assertEquals('customAttributesType', $customAttributes[0]->getName()); + self::assertEquals('xs:string', $customAttributes[0]->getValue()); + + $refAttr = $schema->findAttribute('customAttributesType', 'http://www.ref.com'); + self::assertSame($refAttr->getSchema()->getTargetNamespace(), $customAttributes[0]->getNamespaceURI()); + } + + public function testExternalSchemaReferencingCustomAttributesInformationUnprefixed(): void + { + $dom = new \DOMDocument(); + $dom->loadXML( + ' + + + + + + + + + + '); + $schema = $this->reader->readNodes(iterator_to_array($dom->documentElement->childNodes), 'file.xsd'); + + $myAttribute = $schema->findAttribute('myAttribute', 'http://www.example.com'); + self::assertInstanceOf(AttributeDef::class, $myAttribute); + + $customAttributes = $myAttribute->getCustomAttributes(); + + self::assertCount(1, $customAttributes); + self::assertEquals('customAttributesType', $customAttributes[0]->getName()); + self::assertEquals('string', $customAttributes[0]->getValue()); + + $refAttr = $schema->findAttribute('customAttributesType', 'http://www.ref.com'); + self::assertSame($refAttr->getSchema()->getTargetNamespace(), $customAttributes[0]->getNamespaceURI()); + } } diff --git a/tests/ElementsTest.php b/tests/ElementsTest.php index 6b94675b..2c9ca081 100644 --- a/tests/ElementsTest.php +++ b/tests/ElementsTest.php @@ -272,4 +272,69 @@ public function testSequenceElementDocs(): void $aloneElement = $myGroup->getElements()[0]; self::assertSame('Alone description', $aloneElement->getDoc()); } + + public function testCustomAttributesInformation(): void + { + $schema = $this->reader->readString( + ' + + + ' + ); + + $myElement = $schema->findElement('myElement', 'http://www.example.com'); + self::assertInstanceOf(ElementDef::class, $myElement); + + $customAttributes = $myElement->getCustomAttributes(); + self::assertCount(1, $customAttributes); + self::assertEquals('customAttributes', $customAttributes[0]->getName()); + self::assertEquals('hello', $customAttributes[0]->getValue()); + self::assertEquals('http://www.example.com', $customAttributes[0]->getNamespaceURI()); + } + + public function testDfdlElementCustomAttributesInformation(): void + { + $schema = $this->reader->readString( + ' + + + ' + ); + + $myElement = $schema->findElement('myElement', 'http://www.example.com'); + self::assertInstanceOf(ElementDef::class, $myElement); + + $customAttributes = $myElement->getCustomAttributes(); + $namespaceUri = 'http://www.ogf.org/dfdl/dfdl-1.0/extensions'; + + self::assertCount(5, $customAttributes); + self::assertEquals($namespaceUri, $customAttributes[0]->getNamespaceURI()); + self::assertEquals('encoding', $customAttributes[0]->getName()); + self::assertEquals('iso-8859-1', $customAttributes[0]->getValue()); + + self::assertEquals($namespaceUri, $customAttributes[1]->getNamespaceURI()); + self::assertEquals('initiator', $customAttributes[1]->getName()); + self::assertEquals('UNA', $customAttributes[1]->getValue()); + + self::assertEquals($namespaceUri, $customAttributes[2]->getNamespaceURI()); + self::assertEquals('length', $customAttributes[2]->getName()); + self::assertEquals('6', $customAttributes[2]->getValue()); + + self::assertEquals($namespaceUri, $customAttributes[3]->getNamespaceURI()); + self::assertEquals('lengthKind', $customAttributes[3]->getName()); + self::assertEquals('explicit', $customAttributes[3]->getValue()); + + self::assertEquals($namespaceUri, $customAttributes[4]->getNamespaceURI()); + self::assertEquals('terminator', $customAttributes[4]->getName()); + self::assertEquals('%NL;%WSP*; %WSP*;', $customAttributes[4]->getValue()); + } }