From 8a16637a82f7d3f591316b51b97f67fa6b452bdb Mon Sep 17 00:00:00 2001 From: Asmir Mustafic Date: Tue, 16 Jan 2018 19:33:08 +0100 Subject: [PATCH 1/3] dependent imports --- src/SchemaReader.php | 184 +++++++++++++++++++++---------------------- tests/ImportTest.php | 39 +++++++++ 2 files changed, 131 insertions(+), 92 deletions(-) diff --git a/src/SchemaReader.php b/src/SchemaReader.php index 65de3f4f..0a5c71e7 100644 --- a/src/SchemaReader.php +++ b/src/SchemaReader.php @@ -54,6 +54,11 @@ class SchemaReader */ private $loadedFiles = array(); + /** + * @var Schema[][] + */ + private $loadedSchemas = array(); + /** * @var string[] */ @@ -1061,17 +1066,29 @@ private function loadImport( Schema $schema, DOMElement $node ): Closure { - $base = urldecode($node->ownerDocument->documentURI); - $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation')); $namespace = $node->getAttribute('namespace'); + $schemaLocation = $node->getAttribute('schemaLocation'); + + // postpone schema loading + if ($namespace && !$schemaLocation && !isset(self::$globalSchemaInfo[$namespace])) { + return function () use ($node, $schema, $namespace) { + if (!empty($this->loadedSchemas[$namespace])) { + foreach ($this->loadedSchemas[$namespace] as $s) { + $schema->addSchema($s, $namespace); + } + } + }; + } elseif ($namespace && !$schemaLocation && isset(self::$globalSchemaInfo[$namespace])) { + $schema->addSchema(self::$globalSchemaInfo[$namespace]); + } - $keys = $this->loadImportFreshKeys($namespace, $file); - - foreach ($keys as $key) { - if (isset($this->loadedFiles[$key])) { - $schema->addSchema($this->loadedFiles[$key]); + if ($node->hasAttribute('schemaLocation')) { + $base = urldecode($node->ownerDocument->documentURI); + $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation')); + if (isset($this->loadedFiles[$file])) { + $schema->addSchema($this->loadedFiles[$file]); return function () { }; } @@ -1080,93 +1097,42 @@ private function loadImport( return $this->loadImportFresh($namespace, $schema, $file); } - /** - * @return string[] - */ - private function loadImportFreshKeys( - string $namespace, - string $file - ): array { - $globalSchemaInfo = $this->getGlobalSchemaInfo(); - - $keys = []; - - if (isset($globalSchemaInfo[$namespace])) { - $keys[] = $globalSchemaInfo[$namespace]; - } - - $keys[] = $this->getNamespaceSpecificFileIndex( - $file, - $namespace - ); - - $keys[] = $file; - - return $keys; - } - - private function loadImportFreshCallbacksNewSchema( - string $namespace, + private function createOrUseSchemaForNs( Schema $schema, - string $file + string $namespace ): Schema { - /** - * @var Schema $newSchema - */ - $newSchema = $this->setLoadedFile( - $file, - (('' !== trim($namespace)) ? new Schema() : $schema) - ); - if ('' !== trim($namespace)) { + if (('' !== trim($namespace))) { + $newSchema = new Schema(); $newSchema->addSchema($this->getGlobalSchema()); $schema->addSchema($newSchema); + } else { + $newSchema = $schema; } return $newSchema; } - /** - * @return Closure[] - */ - private function loadImportFreshCallbacks( - string $namespace, - Schema $schema, - string $file - ): array { - /** - * @var string - */ - $file = $file; - - return $this->schemaNode( - $this->loadImportFreshCallbacksNewSchema( - $namespace, - $schema, - $file - ), - $this->getDOM( - isset($this->knownLocationSchemas[$file]) - ? $this->knownLocationSchemas[$file] - : $file - )->documentElement, - $schema - ); - } - private function loadImportFresh( string $namespace, Schema $schema, string $file ): Closure { return function () use ($namespace, $schema, $file) { - foreach ( - $this->loadImportFreshCallbacks( - $namespace, - $schema, - $file - ) as $callback - ) { + + $dom = $this->getDOM( + isset($this->knownLocationSchemas[$file]) + ? $this->knownLocationSchemas[$file] + : $file + ); + + $schemaNew = $this->createOrUseSchemaForNs($schema, $namespace); + + $this->setLoadedFile($file, $schemaNew); + + $callbacks = $this->schemaNode($schemaNew, $dom->documentElement, $schema); + + foreach ($callbacks as $callback) { $callback(); } }; @@ -1177,18 +1143,10 @@ private function loadImportFresh( */ protected $globalSchema; - /** - * @return string[] - */ - public function getGlobalSchemaInfo(): array - { - return self::$globalSchemaInfo; - } - /** * @return Schema */ - public function getGlobalSchema(): Schema + private function getGlobalSchema(): Schema { if (!($this->globalSchema instanceof Schema)) { $callbacks = array(); @@ -1240,12 +1198,49 @@ public function getGlobalSchema(): Schema return $out; } - private function readNode(DOMElement $node, string $file = 'schema.xsd'): Schema + public function readNodes(array $nodes, string $file = null) { - $fileKey = $node->hasAttribute('targetNamespace') ? $this->getNamespaceSpecificFileIndex($file, $node->getAttribute('targetNamespace')) : $file; - $this->setLoadedFile($fileKey, $rootSchema = new Schema()); + $rootSchema = new Schema(); + $rootSchema->addSchema($this->getGlobalSchema()); + $all = array(); + foreach ($nodes as $k => $node) { + if (($node instanceof \DOMElement) && $node->namespaceURI === self::XSD_NS && $node->localName == 'schema') { + + $holderSchema = new Schema(); + $holderSchema->addSchema($this->getGlobalSchema()); + + $this->setLoadedSchema($node, $holderSchema); + + $rootSchema->addSchema($holderSchema); + + $callbacks = $this->schemaNode($holderSchema, $node); + $all = array_merge($callbacks, $all); + } + } + + if ($file) { + $this->setLoadedFile($file, $rootSchema); + } + + foreach ($all as $callback) { + call_user_func($callback); + } + return $rootSchema; + } + + public function readNode(DOMElement $node, string $file = null): Schema + { + $rootSchema = new Schema(); $rootSchema->addSchema($this->getGlobalSchema()); + + if ($file) { + $this->setLoadedFile($file, $rootSchema); + } + + $this->setLoadedSchema($node, $rootSchema); + + $callbacks = $this->schemaNode($rootSchema, $node); foreach ($callbacks as $callback) { @@ -1398,11 +1393,16 @@ private function findSomethingLikeAttributeGroup( $addToThis->addAttribute($attribute); } - private function setLoadedFile(string $key, Schema $schema): Schema + private function setLoadedFile(string $key, Schema $schema): void { $this->loadedFiles[$key] = $schema; + } - return $schema; + private function setLoadedSchema(DOMNode $node, Schema $schema): void + { + if ($node->hasAttribute('targetNamespace')) { + $this->loadedSchemas[$node->getAttribute('targetNamespace')][] = $schema; + } } private function setSchemaThingsFromNode( diff --git a/tests/ImportTest.php b/tests/ImportTest.php index b5303a76..cfc8f383 100644 --- a/tests/ImportTest.php +++ b/tests/ImportTest.php @@ -4,6 +4,9 @@ namespace GoetasWebservices\XML\XSDReader\Tests; +use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem; +use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef; + class ImportTest extends BaseTest { public function testBase() @@ -37,4 +40,40 @@ public function testBase() $this->assertSame($remoteAttr, $localAttrs[0]); } + + public function testBaseNode() + { + $dom = new \DOMDocument(); + $dom->loadXML(' + + + + '); + $schema = $this->reader->readNode($dom->documentElement); + $attr = $schema->findAttribute('myAttribute', 'http://www.example.com'); + + $this->assertInstanceOf(AttributeItem::class, $attr); + } + + public function testDependentImport() + { + $dom = new \DOMDocument(); + $dom->loadXML(' + + + + + + + + + + + + '); + $schema = $this->reader->readNodes(iterator_to_array($dom->documentElement->childNodes)); + + $this->assertInstanceOf(ElementDef::class, $schema->findElement("outerEl", "http://tempuri.org/1")); + + } } From 921ddb4856d7f64d544c89802395b1bccbc1a71f Mon Sep 17 00:00:00 2001 From: Asmir Mustafic Date: Tue, 16 Jan 2018 19:42:38 +0100 Subject: [PATCH 2/3] fix phpstan errors --- src/SchemaReader.php | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/src/SchemaReader.php b/src/SchemaReader.php index 0a5c71e7..064a311f 100644 --- a/src/SchemaReader.php +++ b/src/SchemaReader.php @@ -1072,26 +1072,24 @@ private function loadImport( // postpone schema loading if ($namespace && !$schemaLocation && !isset(self::$globalSchemaInfo[$namespace])) { - return function () use ($node, $schema, $namespace) { + return function () use ($schema, $namespace) { if (!empty($this->loadedSchemas[$namespace])) { foreach ($this->loadedSchemas[$namespace] as $s) { $schema->addSchema($s, $namespace); } } }; - } elseif ($namespace && !$schemaLocation && isset(self::$globalSchemaInfo[$namespace])) { - $schema->addSchema(self::$globalSchemaInfo[$namespace]); + } elseif ($namespace && !$schemaLocation && isset($this->globalSchema[$namespace])) { + $schema->addSchema($this->globalSchema[$namespace]); } - if ($node->hasAttribute('schemaLocation')) { - $base = urldecode($node->ownerDocument->documentURI); - $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation')); + $base = urldecode($node->ownerDocument->documentURI); + $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation')); - if (isset($this->loadedFiles[$file])) { - $schema->addSchema($this->loadedFiles[$file]); - return function () { - }; - } + if (isset($this->loadedFiles[$file])) { + $schema->addSchema($this->loadedFiles[$file]); + return function () { + }; } return $this->loadImportFresh($namespace, $schema, $file); @@ -1203,6 +1201,10 @@ public function readNodes(array $nodes, string $file = null) $rootSchema = new Schema(); $rootSchema->addSchema($this->getGlobalSchema()); + if ($file !== null) { + $this->setLoadedFile($file, $rootSchema); + } + $all = array(); foreach ($nodes as $k => $node) { if (($node instanceof \DOMElement) && $node->namespaceURI === self::XSD_NS && $node->localName == 'schema') { @@ -1219,10 +1221,6 @@ public function readNodes(array $nodes, string $file = null) } } - if ($file) { - $this->setLoadedFile($file, $rootSchema); - } - foreach ($all as $callback) { call_user_func($callback); } @@ -1234,7 +1232,7 @@ public function readNode(DOMElement $node, string $file = null): Schema $rootSchema = new Schema(); $rootSchema->addSchema($this->getGlobalSchema()); - if ($file) { + if ($file !== null) { $this->setLoadedFile($file, $rootSchema); } @@ -1250,17 +1248,6 @@ public function readNode(DOMElement $node, string $file = null): Schema return $rootSchema; } - /** - * It is possible that a single file contains multiple nodes, for instance in a WSDL file. - * - * Each of these nodes typically target a specific namespace. Append the target namespace to the - * file to distinguish between multiple schemas in a single file. - */ - private function getNamespaceSpecificFileIndex(string $file, string $targetNamespace): string - { - return $file.'#'.$targetNamespace; - } - /** * @throws IOException */ @@ -1398,7 +1385,7 @@ private function setLoadedFile(string $key, Schema $schema): void $this->loadedFiles[$key] = $schema; } - private function setLoadedSchema(DOMNode $node, Schema $schema): void + private function setLoadedSchema(DOMElement $node, Schema $schema): void { if ($node->hasAttribute('targetNamespace')) { $this->loadedSchemas[$node->getAttribute('targetNamespace')][] = $schema; From 6bd22641c17d9d1e45141dad1248c3bc8afe83f2 Mon Sep 17 00:00:00 2001 From: Asmir Mustafic Date: Wed, 17 Jan 2018 19:41:41 +0100 Subject: [PATCH 3/3] style --- src/SchemaReader.php | 7 ++----- tests/ImportTest.php | 3 +-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/SchemaReader.php b/src/SchemaReader.php index 064a311f..5fb1d66e 100644 --- a/src/SchemaReader.php +++ b/src/SchemaReader.php @@ -1066,7 +1066,6 @@ private function loadImport( Schema $schema, DOMElement $node ): Closure { - $namespace = $node->getAttribute('namespace'); $schemaLocation = $node->getAttribute('schemaLocation'); @@ -1088,6 +1087,7 @@ private function loadImport( if (isset($this->loadedFiles[$file])) { $schema->addSchema($this->loadedFiles[$file]); + return function () { }; } @@ -1099,7 +1099,6 @@ private function createOrUseSchemaForNs( Schema $schema, string $namespace ): Schema { - if (('' !== trim($namespace))) { $newSchema = new Schema(); $newSchema->addSchema($this->getGlobalSchema()); @@ -1117,7 +1116,6 @@ private function loadImportFresh( string $file ): Closure { return function () use ($namespace, $schema, $file) { - $dom = $this->getDOM( isset($this->knownLocationSchemas[$file]) ? $this->knownLocationSchemas[$file] @@ -1208,7 +1206,6 @@ public function readNodes(array $nodes, string $file = null) $all = array(); foreach ($nodes as $k => $node) { if (($node instanceof \DOMElement) && $node->namespaceURI === self::XSD_NS && $node->localName == 'schema') { - $holderSchema = new Schema(); $holderSchema->addSchema($this->getGlobalSchema()); @@ -1224,6 +1221,7 @@ public function readNodes(array $nodes, string $file = null) foreach ($all as $callback) { call_user_func($callback); } + return $rootSchema; } @@ -1238,7 +1236,6 @@ public function readNode(DOMElement $node, string $file = null): Schema $this->setLoadedSchema($node, $rootSchema); - $callbacks = $this->schemaNode($rootSchema, $node); foreach ($callbacks as $callback) { diff --git a/tests/ImportTest.php b/tests/ImportTest.php index cfc8f383..7e698623 100644 --- a/tests/ImportTest.php +++ b/tests/ImportTest.php @@ -73,7 +73,6 @@ public function testDependentImport() '); $schema = $this->reader->readNodes(iterator_to_array($dom->documentElement->childNodes)); - $this->assertInstanceOf(ElementDef::class, $schema->findElement("outerEl", "http://tempuri.org/1")); - + $this->assertInstanceOf(ElementDef::class, $schema->findElement('outerEl', 'http://tempuri.org/1')); } }