Skip to content

Commit

Permalink
Merge pull request #83 from veewee/collect-meta-info
Browse files Browse the repository at this point in the history
Collect meta attributes from XSD files
  • Loading branch information
goetas authored Jun 4, 2024
2 parents 74d1991 + 52e3f63 commit f4bdcbb
Show file tree
Hide file tree
Showing 11 changed files with 1,354 additions and 1,046 deletions.
2,129 changes: 1,085 additions & 1,044 deletions clover.xml

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/Schema/Attribute/AbstractAttributeItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/Schema/Attribute/AttributeSingle.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
45 changes: 45 additions & 0 deletions src/Schema/CustomAttribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace GoetasWebservices\XML\XSDReader\Schema;

/**
* Contains the information of additional custom attributes that are not part of the XSD specification.
*
* For example:
* <xsd:element name="myElement" dfdl:encoding="iso-8859-1" />
*/
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;
}
}
18 changes: 18 additions & 0 deletions src/Schema/CustomAttributeContainerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace GoetasWebservices\XML\XSDReader\Schema;

interface CustomAttributeContainerInterface
{
/**
* @param list<CustomAttribute> $customAttributes
*/
public function setCustomAttributes(array $customAttributes): void;

/**
* @return list<CustomAttribute>
*/
public function getCustomAttributes(): array;
}
29 changes: 29 additions & 0 deletions src/Schema/CustomAttributeContainerTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace GoetasWebservices\XML\XSDReader\Schema;

trait CustomAttributeContainerTrait
{
/**
* @var list<CustomAttribute>
*/
protected array $customAttributes = [];

/**
* @return list<CustomAttribute>
*/
public function getCustomAttributes(): array
{
return $this->customAttributes;
}

/**
* @param list<CustomAttribute> $customAttributes
*/
public function setCustomAttributes(array $customAttributes): void
{
$this->customAttributes = $customAttributes;
}
}
3 changes: 3 additions & 0 deletions src/Schema/Element/AbstractElementSingle.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/Schema/Element/ElementSingle.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
24 changes: 24 additions & 0 deletions src/SchemaReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<CustomAttribute>
*/
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(
Expand Down Expand Up @@ -1456,6 +1478,8 @@ private function fillElement(AbstractElementSingle $element, \DOMElement $node):
$element->setLocal(true);
}
}

$element->setCustomAttributes($this->loadCustomAttributesForElement($element, $node));
}

private function addAttributeFromAttributeOrRef(
Expand Down
78 changes: 78 additions & 0 deletions tests/AttributesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
'
<xs:schema targetNamespace="http://www.example.com" xmlns:tns="http://www.example.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:attribute name="myAttribute" type="xs:string" tns:customAttributes="hello" />
</xs:schema>'
);

$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(
'
<types xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:schema targetNamespace="http://www.ref.com">
<xs:attribute name="customAttributesType" type="xs:string" />
</xs:schema>
<xs:schema targetNamespace="http://www.example.com" xmlns:ref="http://www.ref.com">
<xs:import namespace="http://www.ref.com" />
<xs:attribute name="myAttribute" type="xs:string" ref:customAttributesType="xs:string" />
</xs:schema>
</types>
');
$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(
'
<types xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:schema targetNamespace="http://www.ref.com">
<xs:attribute name="customAttributesType" type="xs:string" />
</xs:schema>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.com" xmlns:ref="http://www.ref.com">
<import namespace="http://www.ref.com" />
<attribute name="myAttribute" type="string" ref:customAttributesType="string" />
</schema>
</types>
');
$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());
}
}
65 changes: 65 additions & 0 deletions tests/ElementsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
'
<xs:schema targetNamespace="http://www.example.com" xmlns:tns="http://www.example.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="myElement" type="xs:string" tns:customAttributes="hello" />
</xs:schema>'
);

$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(
'
<xs:schema targetNamespace="http://www.example.com" xmlns:tns="http://www.example.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element
xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/extensions"
dfdl:encoding="iso-8859-1"
dfdl:initiator="UNA"
dfdl:length="6"
dfdl:lengthKind="explicit"
dfdl:terminator="%NL;%WSP*; %WSP*;"
minOccurs="0"
name="myElement"
type="xs:string" />
</xs:schema>'
);

$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());
}
}

0 comments on commit f4bdcbb

Please sign in to comment.