From 1ccae4d30f7d749deb90a33432c52a5dc4b17480 Mon Sep 17 00:00:00 2001 From: Kacper Stasik Date: Fri, 3 Mar 2017 12:44:11 +0100 Subject: [PATCH] basic redefine support: https://www.w3.org/TR/xmlschema11-1/#modify-schema --- src/SchemaReader.php | 42 +++++++++++++++++++++++++-- tests/RedefineTest.php | 66 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 tests/RedefineTest.php diff --git a/src/SchemaReader.php b/src/SchemaReader.php index 8b742854..dc055a90 100644 --- a/src/SchemaReader.php +++ b/src/SchemaReader.php @@ -164,6 +164,9 @@ private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = n case 'import': $functions[] = $this->loadImport($schema, $childNode); break; + case 'redefine': + $functions[] = $this->loadRedefine($schema, $childNode); + break; case 'element': $functions[] = $this->loadElementDef($schema, $childNode); break; @@ -204,7 +207,7 @@ private function loadElement(Schema $schema, DOMElement $node) $xp = new \DOMXPath($node->ownerDocument); $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema'); - + if ($xp->query('ancestor::xs:choice', $node)->length) { $element->setMin(0); } @@ -639,6 +642,41 @@ private function fillItem(Item $element, DOMElement $node) } } + private function loadRedefine(Schema $schema, DOMElement $node) + { + $base = urldecode($node->ownerDocument->documentURI); + $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute("schemaLocation")); + + 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); + + $callbacks = $this->schemaNode($redefined, $node, $schema); + } + else{ + $redefined = new Schema(); + $redefined->addSchema($this->getGlobalSchema()); + + $xml = $this->getDOM(isset($this->knownLocationSchemas[$file]) ? $this->knownLocationSchemas[$file] : $file); + + $callbacks = $this->schemaNode($redefined, $xml->documentElement, $schema); + + $schema->addSchema($redefined); + } + + return function () use ($callbacks) { + foreach ($callbacks as $callback) { + call_user_func($callback); + } + }; + } + private function loadImport(Schema $schema, DOMElement $node) { $base = urldecode($node->ownerDocument->documentURI); @@ -722,7 +760,7 @@ public function getGlobalSchema() /** * @param DOMNode $node * @param string $file - * + * * @return Schema */ public function readNode(DOMNode $node, $file = 'schema.xsd') diff --git a/tests/RedefineTest.php b/tests/RedefineTest.php new file mode 100644 index 00000000..d8d03a11 --- /dev/null +++ b/tests/RedefineTest.php @@ -0,0 +1,66 @@ +reader->readString( + ' + + + + + + + + + + ', 'http://www.example.com/xsd.xsd'); + + + $schema = $this->reader->readString( + ' + + + + + + + + + + + + + + + '); + + // 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', $type); + + $children = array(); + foreach($type->getElements() as $element){ + $children[] = $element->getName(); + } + + $this->assertContains('generation', $children); + } +}