Skip to content

Commit 3bda501

Browse files
committed
Fix mutable nodeList reference during traversal
1 parent 6123139 commit 3bda501

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

src/Xml/Dom/Traverser/Traverser.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use DOMNode;
88
use function VeeWee\Xml\Dom\Locator\Attribute\attributes_list;
9+
use function VeeWee\Xml\Dom\Locator\Node\children;
910

1011
final class Traverser
1112
{
@@ -30,7 +31,7 @@ public function traverse(DOMNode $node): DOMNode
3031
$this->traverse($attribute);
3132
}
3233

33-
foreach ($node->childNodes as $child) {
34+
foreach (children($node) as $child) {
3435
$this->traverse($child);
3536
}
3637

tests/Xml/Dom/Traverser/TraverserTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
use VeeWee\Xml\Dom\Traverser\Traverser;
1212
use VeeWee\Xml\Dom\Traverser\Visitor\AbstractVisitor;
1313
use function VeeWee\Xml\Dom\Builder\attribute;
14+
use function VeeWee\Xml\Dom\Configurator\comparable;
1415
use function VeeWee\Xml\Dom\Locator\document_element;
1516
use function VeeWee\Xml\Dom\Mapper\xml_string;
1617
use function VeeWee\Xml\Dom\Predicate\is_attribute;
1718
use function VeeWee\Xml\Dom\Predicate\is_element;
19+
use function VeeWee\Xml\Dom\Predicate\is_empty_node;
1820
use function VeeWee\Xml\Dom\Predicate\is_non_empty_text;
1921
use function VeeWee\Xml\Dom\Predicate\is_whitespace;
2022

@@ -130,4 +132,50 @@ public function onNodeLeave(DOMNode $node): Action
130132

131133
static::assertXmlStringEqualsXmlString($doc->toXmlString(), '<hello enter="yes" leave="yes" />');
132134
}
135+
136+
/** @test */
137+
public function it_can_recursively_remove_empty_nodes(): void
138+
{
139+
$doc = Document::fromXmlString(<<<EOXML
140+
<movies>
141+
<movie>
142+
<name>Terminator</name>
143+
<genre>
144+
<action />
145+
<romance />
146+
</genre>
147+
<prices>
148+
<oscar />
149+
</prices>
150+
</movie>
151+
</movies>
152+
EOXML
153+
);
154+
155+
$transformedNode = $doc->traverse(new class extends AbstractVisitor {
156+
public function onNodeLeave(\DOMNode $node): Action
157+
{
158+
if (!is_element($node)) {
159+
return new Action\Noop();
160+
}
161+
162+
if (trim($node->textContent) !== '') {
163+
return new Action\Noop();
164+
}
165+
166+
return new Action\RemoveNode();
167+
}
168+
});
169+
170+
$actual = Document::fromXmlNode($transformedNode, comparable());
171+
$expected = Document::fromXmlString(<<<EOXML
172+
<movies>
173+
<movie>
174+
<name>Terminator</name>
175+
</movie>
176+
</movies>
177+
EOXML, comparable());
178+
179+
self::assertSame($actual->toXmlString(), $expected->toXmlString());
180+
}
133181
}

0 commit comments

Comments
 (0)