diff --git a/src/Nodes/XMLNode.php b/src/Nodes/XMLNode.php index 263f71b..454cec1 100644 --- a/src/Nodes/XMLNode.php +++ b/src/Nodes/XMLNode.php @@ -11,6 +11,7 @@ public function __construct( public string $name, public array $attributes = [], public ?string $content = null, + public ?string $parentName = null, ) { } } diff --git a/src/Nodes/XMLNodeClose.php b/src/Nodes/XMLNodeClose.php index 55cd481..2ed495e 100644 --- a/src/Nodes/XMLNodeClose.php +++ b/src/Nodes/XMLNodeClose.php @@ -5,8 +5,9 @@ class XMLNodeClose extends XMLNode { public function __construct( - string $name + string $name, + ?string $parentName, ) { - parent::__construct($name, attributes: [], content: null); + parent::__construct($name, attributes: [], content: null, parentName: $parentName); } } diff --git a/src/Nodes/XMLNodeOpen.php b/src/Nodes/XMLNodeOpen.php index 29f7748..9ae7fb2 100644 --- a/src/Nodes/XMLNodeOpen.php +++ b/src/Nodes/XMLNodeOpen.php @@ -5,9 +5,10 @@ class XMLNodeOpen extends XMLNode { public function __construct( - string $name, - array $attributes, + string $name, + array $attributes, + ?string $parentName, ) { - parent::__construct($name, $attributes, content: null); + parent::__construct($name, $attributes, content: null, parentName: $parentName); } } diff --git a/src/XMLParser.php b/src/XMLParser.php index 6f6a957..6264a61 100644 --- a/src/XMLParser.php +++ b/src/XMLParser.php @@ -88,6 +88,7 @@ public function startXML(\XMLParser $parser, string $tagName, array $attributes) $this->nodesQueue[] = new Nodes\XMLNodeOpen( name: $this->currentTagName, attributes: $this->currentTagAttributes, + parentName: end($this->nodeNamesStack) ?: null ); $this->nodeNamesStack[] = $tagName; @@ -100,19 +101,21 @@ public function charXML(\XMLParser $parser, string $tagContent): void name: $this->currentTagName, attributes: $this->currentTagAttributes, content: $tagContent, + parentName: array_slice($this->nodeNamesStack, -2, 1)[0] ?: null ); } public function endXML(\XMLParser $parser, string $tagName): void { + // Pop the node name off the end of stack + array_pop($this->nodeNamesStack); + // append to the queue of items to iterate over $this->nodesQueue[] = new Nodes\XMLNodeClose( name: $tagName, + parentName: end($this->nodeNamesStack) ?: null ); - // Pop the node name off the end of stack - array_pop($this->nodeNamesStack); - // and update the current tag name to properly handle consecutive closing tag and whitespaces // e.g. \n\n $this->currentTagName = end($this->nodeNamesStack); diff --git a/tests/XMLParserCDataTest.php b/tests/XMLParserCDataTest.php index b74633d..8639e78 100644 --- a/tests/XMLParserCDataTest.php +++ b/tests/XMLParserCDataTest.php @@ -37,5 +37,6 @@ public function testCDataIsProperlyParsed(): void $this->assertInstanceOf(XMLNodeContent::class, $node); $this->assertStringStartsWith("

\n ", trim($node->content)); + $this->assertEquals('item', $node->parentName); } } diff --git a/tests/XMLParserLargeFileTest.php b/tests/XMLParserLargeFileTest.php index ef13f5b..cbeb747 100644 --- a/tests/XMLParserLargeFileTest.php +++ b/tests/XMLParserLargeFileTest.php @@ -35,6 +35,7 @@ public function testIterateByNodeContent() foreach($this->getParser()->iterateByNodeContent(name: 'loc') as $node) { $this->assertInstanceOf(XMLNodeContent::class, $node); $this->assertEquals('loc', $node->name); + $this->assertEquals('url', $node->parentName); $this->assertStringStartsWith('http', $node->content); $cnt++; diff --git a/tests/XMLParserTest.php b/tests/XMLParserTest.php index a6489cd..ab059cf 100644 --- a/tests/XMLParserTest.php +++ b/tests/XMLParserTest.php @@ -24,6 +24,7 @@ public function testParsesTheOpeningTags(): void $this->assertInstanceOf(XMLNodeOpen::class, $sitemapIndex); $this->assertEquals('sitemapindex', $sitemapIndex->name); + $this->assertNull($sitemapIndex->parentName, 'Root nodes will get null as their parent'); $this->assertEquals('http://www.sitemaps.org/schemas/sitemap/0.9', $sitemapIndex->attributes['xmlns'] ?? null); } @@ -39,6 +40,7 @@ public function testParsesTheClosingTags(): void $this->assertInstanceOf(XMLNodeClose::class, $closingTag); $this->assertEquals('sitemapindex', $closingTag->name); + $this->assertNull($closingTag->parentName); } public function testParsesTheLocNodes(): void @@ -48,6 +50,7 @@ public function testParsesTheLocNodes(): void foreach($this->getParser() as $item) { if ($item instanceof XMLNodeContent && $item->name === 'loc') { $locations[] = $item->content; + $this->assertEquals('sitemap', $item->parentName); } } diff --git a/tests/XMLParserWhitespacesTest.php b/tests/XMLParserWhitespacesTest.php index 8beaf92..df0a577 100644 --- a/tests/XMLParserWhitespacesTest.php +++ b/tests/XMLParserWhitespacesTest.php @@ -30,5 +30,6 @@ public function testProperlyReportWhitespacesBetweenClosingTags(): void $this->assertCount(1, $locNodesContent); $this->assertEquals('https://elecena.pl/sitemap-001-search.xml.gz', $locNodesContent[0]->content); + $this->assertEquals('sitemap', $locNodesContent[0]->parentName); } }