Skip to content

Commit

Permalink
Collect meta attributes from XSD files
Browse files Browse the repository at this point in the history
  • Loading branch information
veewee committed May 28, 2024
1 parent ee51ff5 commit fdccf9e
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 0 deletions.
22 changes: 22 additions & 0 deletions src/Schema/Attribute/AbstractAttributeItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace GoetasWebservices\XML\XSDReader\Schema\Attribute;

use GoetasWebservices\XML\XSDReader\Schema\Item;
use GoetasWebservices\XML\XSDReader\Schema\MetaInformation;

abstract class AbstractAttributeItem extends Item implements AttributeSingle
{
Expand All @@ -18,6 +19,11 @@ abstract class AbstractAttributeItem extends Item implements AttributeSingle

protected string $use = self::USE_OPTIONAL;

/**
* @var list<MetaInformation>
*/
protected array $meta = [];

public function getFixed(): ?string
{
return $this->fixed;
Expand Down Expand Up @@ -67,4 +73,20 @@ public function setUse(string $use): void
{
$this->use = $use;
}

/**
* @return list<MetaInformation>
*/
public function getMeta(): array
{
return $this->meta;
}

/**
* @param list<MetaInformation> $meta
*/
public function setMeta(array $meta): void
{
$this->meta = $meta;
}
}
11 changes: 11 additions & 0 deletions src/Schema/Attribute/AttributeSingle.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace GoetasWebservices\XML\XSDReader\Schema\Attribute;

use GoetasWebservices\XML\XSDReader\Schema\MetaInformation;
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;

interface AttributeSingle extends AttributeItem
Expand Down Expand Up @@ -35,4 +36,14 @@ public function setNil(bool $nil): void;
public function getUse(): ?string;

public function setUse(string $use): void;

/**
* @param list<MetaInformation> $meta
*/
public function setMeta(array $meta): void;

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

declare(strict_types=1);

namespace GoetasWebservices\XML\XSDReader\Schema;

/**
* Contains the information of additional attributes that are not part of the XSD specification:
* Formats like WSDLs can allow additional attributes to be added to the schemas.
* This class is used to store this information.
*/
class MetaInformation
{
private Schema $schema;
private string $name;
private string $value;

public function __construct(
Schema $schema,
string $name,
string $value
) {
$this->schema = $schema;
$this->name = $name;
$this->value = $value;
}

public function getSchema(): Schema
{
return $this->schema;
}

public function getName(): string
{
return $this->name;
}

public function getValue(): string
{
return $this->value;
}
}
36 changes: 36 additions & 0 deletions src/SchemaReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@
use GoetasWebservices\XML\XSDReader\Schema\Element\InterfaceSetFixed;
use GoetasWebservices\XML\XSDReader\Schema\Element\InterfaceSetMinMax;
use GoetasWebservices\XML\XSDReader\Schema\Element\Sequence;
use GoetasWebservices\XML\XSDReader\Schema\Exception\SchemaException;
use GoetasWebservices\XML\XSDReader\Schema\Exception\TypeNotFoundException;
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Base;
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Extension;
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Restriction;
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\RestrictionType;
use GoetasWebservices\XML\XSDReader\Schema\Item;
use GoetasWebservices\XML\XSDReader\Schema\MetaInformation;
use GoetasWebservices\XML\XSDReader\Schema\Schema;
use GoetasWebservices\XML\XSDReader\Schema\SchemaItem;
use GoetasWebservices\XML\XSDReader\Schema\Type\BaseComplexType;
Expand Down Expand Up @@ -236,6 +238,27 @@ private function fillAttribute(AttributeSingle $attribute, \DOMElement $node): v
if ($node->hasAttribute('use')) {
$attribute->setUse($node->getAttribute('use'));
}

$attribute->setMeta($this->loadMetaAttributesForElement($attribute, $node));
}

/**
* @return list<MetaInformation>
*/
private function loadMetaAttributesForElement(SchemaItem $item, \DOMElement $node): array
{
$meta = [];
foreach ($node->attributes as $attr) {
if (null !== $attr->namespaceURI && self::XSD_NS !== $attr->namespaceURI) {
$meta[] = new MetaInformation(
$this->findSchemaForNamespace($item->getSchema(), $attr->namespaceURI),
$attr->name,
$attr->value
);
}
}

return $meta;
}

private function loadAttributeOrElementDef(
Expand Down Expand Up @@ -1088,6 +1111,19 @@ private function findType(Schema $schema, \DOMElement $node, string $typeName):
throw new TypeException(sprintf("Can't find %s named {%s}#%s, at line %d in %s ", 'type', $namespace, $name, $node->getLineNo(), $node->ownerDocument->documentURI));
}

public function findSchemaForNamespace(Schema $currentSchema, string $namespace): Schema
{
if ($currentSchema->getTargetNamespace() === $namespace) {
return $currentSchema;
}

if (array_key_exists($namespace, $this->loadedSchemas) && count($this->loadedSchemas[$namespace]) > 0) {
return $this->loadedSchemas[$namespace][0];
}

throw new SchemaException(sprintf("Can't find schema for namespace %s", $namespace));
}

private function fillItem(Item $element, \DOMElement $node, ?\DOMElement $parentNode = null): void
{
if ($element instanceof ElementDef) {
Expand Down
48 changes: 48 additions & 0 deletions tests/AttributesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,52 @@ public function testAttributeUseOverriding(): void
self::assertEquals('language', $attribute->getType()->getName());
self::assertEquals(AttributeSingle::USE_REQUIRED, $attribute->getUse());
}

public function testMetaInformation(): 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:meta="hello" />
</xs:schema>'
);

$myAttribute = $schema->findAttribute('myAttribute', 'http://www.example.com');
self::assertInstanceOf(AttributeDef::class, $myAttribute);

$meta = $myAttribute->getMeta();
self::assertCount(1, $meta);
self::assertEquals('meta', $meta[0]->getName());
self::assertEquals('hello', $meta[0]->getValue());
self::assertSame($myAttribute->getSchema(), $meta[0]->getSchema());
}

public function testExternalSchemaReferencingMetaInformation(): 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="meta" 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:meta="hello" />
</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);

$meta = $myAttribute->getMeta();
self::assertCount(1, $meta);
self::assertEquals('meta', $meta[0]->getName());
self::assertEquals('hello', $meta[0]->getValue());

$refAttr = $schema->findAttribute('meta', 'http://www.ref.com');
self::assertSame($refAttr->getSchema(), $meta[0]->getSchema());
}
}

0 comments on commit fdccf9e

Please sign in to comment.