Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/SchemaReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ function (
case 'import':
$callback = $this->loadImport($schema, $childNode);
break;
case 'redefine':
$callback = $this->loadRedefine($schema, $childNode);
break;
case 'element':
$callback = $this->loadElementDef($schema, $childNode);
break;
Expand Down Expand Up @@ -1170,6 +1173,32 @@ private function loadImport(
return $this->loadImportFresh($namespace, $schema, $file);
}

private function loadRedefine(Schema $schema, DOMElement $node): Closure
{
$base = urldecode($node->ownerDocument->documentURI);
$file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation'));

@goetas goetas Apr 2, 2019

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure that redefine semantics is applied on schemaLocation and on the target namespace?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure that it implements all semantics defined for it but it works for the case where additional Elements and Types are added to a namespace. this is what is covered in the test cases from the original PR and also in the case I extracted from the spec I am currently working with.


if (isset($this->loadedFiles[$file])) {
/* @var $redefined Schema */
$redefined = clone $this->loadedFiles[$file];

if ($schema->getTargetNamespace() !== $redefined->getTargetNamespace()) {
$redefined->setTargetNamespace($schema->getTargetNamespace());
}

$schema->addSchema($redefined);

return function () use ($redefined, $node, $schema): void {
$callbacks = $this->schemaNode($redefined, $node, $schema);
foreach ($callbacks as $callback) {
$callback();
}
};
}

return $this->loadImportFresh((string) $schema->getTargetNamespace(), $schema, $file);
}

private function createOrUseSchemaForNs(
Schema $schema,
string $namespace
Expand Down
98 changes: 98 additions & 0 deletions tests/RedefineTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

declare(strict_types=1);

namespace GoetasWebservices\XML\XSDReader\Tests;

use GoetasWebservices\XML\XSDReader\Schema\Schema;

class RedefineTest extends BaseTest
{
public function testBase()
{
$remoteSchema = $this->reader->readString(
'
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="personName">
<xs:sequence>
<xs:element name="title" minOccurs="0"/>
<xs:element name="forename" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>

<xs:element name="addressee" type="personName"/>
</xs:schema>', 'http://www.example.com/xsd.xsd');

$schema = $this->reader->readString(
'
<xs:schema targetNamespace="http://www.user.com" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ex="http://www.example.com">
<xs:redefine schemaLocation="http://www.example.com/xsd.xsd">
<xs:complexType name="personName">
<xs:complexContent>
<xs:extension base="personName">
<xs:sequence>
<xs:element name="generation" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:redefine>

<xs:element name="author" type="personName"/>
</xs:schema>');

// check if schema is not included
// we don't want to redefine original schema
$this->assertNotContains($remoteSchema, $schema->getSchemas(), '', true);

/* @var $localAttr \GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef */

// it should inherit namespace of main schema
$localAttr = $schema->findElement('addressee', 'http://www.user.com');
$this->assertNotNull($localAttr);

// find author element
$localAttr = $schema->findElement('author', 'http://www.user.com');
$this->assertNotNull($localAttr);

/* @var $type \GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType */
$type = $localAttr->getType();

$this->assertInstanceOf(\GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType::class, $type);

$children = array();
foreach ($type->getElements() as $element) {
$children[] = $element->getName();
}

$this->assertContains('generation', $children);
}

public function testReadSchemaLocation()
{
$schema = $this->reader->readFile(__DIR__.'/schema/extend-components.xsd');
$this->assertInstanceOf(Schema::class, $schema);

$this->assertEquals('spec:example:xsd:CommonBasicComponents-1.0', $schema->getTargetNamespace());

// defined in /schema/base-components.xsd
$dateElement = $schema->findElement('Date', 'spec:example:xsd:CommonBasicComponents-1.0');
$this->assertNotNull($dateElement);
$this->assertInstanceOf(\GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef::class, $dateElement);
$type = $dateElement->getType();
$this->assertEquals('DateType', $type->getName());
$this->assertInstanceOf(\GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType::class, $type);

$dateType = $schema->findType('DateType', 'spec:example:xsd:CommonBasicComponents-1.0');
$this->assertNotNull($dateType);
$this->assertInstanceOf(\GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType::class, $dateType);

// defined in /schema/extend-components.xsd
$deliveryDateElement = $schema->findElement('DeliveryDate', 'spec:example:xsd:CommonBasicComponents-1.0');
$this->assertNotNull($deliveryDateElement);
$this->assertInstanceOf(\GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef::class, $deliveryDateElement);
$type = $deliveryDateElement->getType();
$this->assertEquals('DateType', $type->getName());
$this->assertInstanceOf(\GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType::class, $type);
}
}
15 changes: 15 additions & 0 deletions tests/schema/base-components.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="spec:example:xsd:CommonBasicComponents-1.0"
targetNamespace="spec:example:xsd:CommonBasicComponents-1.0"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:element name="Date" type="DateType"/>
<xsd:element name="Indicator" type="IndicatorType"/>

<xsd:complexType name="DateType">
</xsd:complexType>
<xsd:complexType name="IndicatorType">
</xsd:complexType>

</xsd:schema>
19 changes: 19 additions & 0 deletions tests/schema/extend-components.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="iso-8859-1" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="spec:example:xsd:CommonBasicComponents-1.0"
targetNamespace="spec:example:xsd:CommonBasicComponents-1.0"
elementFormDefault="qualified"
attributeFormDefault="unqualified">

<xsd:redefine schemaLocation="base-components.xsd">
</xsd:redefine>

<xsd:element name="DeliveryDate" type="DateType">
<xsd:annotation><xsd:documentation>Lieferdatum</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="BacklogIndicator" type="IndicatorType">
<xsd:annotation><xsd:documentation>Indikator</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:schema>