Skip to content

Commit 5ea52aa

Browse files
dominik-vasicekDominik Vašíček
andauthored
fix case in which closing tag preceding opening tag acts as pair, creating negative length item to be flushed (#78)
Co-authored-by: Dominik Vašíček <dominik.vasicek@trayto.com>
1 parent 46176a5 commit 5ea52aa

4 files changed

Lines changed: 53 additions & 2 deletions

File tree

src/XmlStringStreamer/Parser/UniqueNode.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ private function checkShortClosingTag($workingBlob, $len) {
134134
*/
135135
protected function getClosingTagPos()
136136
{
137-
$endPositionInBlob = strpos($this->workingBlob, "</" . $this->options["uniqueNode"] . ">");
137+
$endPositionInBlob = strpos($this->workingBlob, "</" . $this->options["uniqueNode"] . ">", $this->startPos);
138138
if ($endPositionInBlob === false) {
139139

140140
if (isset($this->options["checkShortClosing"]) && $this->options["checkShortClosing"] === true) {

tests/integration/XmlStringStreamer/XmlStringStreamerIntegrationTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,4 +317,26 @@ public function test_StringWalker_parser_reset_working_blob()
317317
$parser->reset();
318318
self::assertSame("\n <item>0</item>", $streamer->getNode());
319319
}
320+
321+
public function test_UniqueNode_parser_stream_seeking()
322+
{
323+
$filePath = __dir__ . '/../../xml/stream_seeking.xml';
324+
$fileHandle = fopen($filePath, 'rb');
325+
326+
$stream = new XmlStringStreamer\Stream\File($fileHandle, 50);
327+
$parser = new UniqueNode(["uniqueNode" => 'item']);
328+
$streamer = new XmlStringStreamer($parser, $stream);
329+
330+
self::assertSame('<item>first item to read</item>', $streamer->getNode());
331+
332+
/**
333+
* @see /tests/xml/stream_seeking.xml
334+
* hash character is used as seek target in file, creating case where closing tag precedes opening tag
335+
*/
336+
$seekTargetPosition = strpos(file_get_contents($filePath), '#');
337+
fseek($fileHandle, $seekTargetPosition);
338+
$parser->reset();
339+
340+
self::assertSame('<item>second item to read</item>', $streamer->getNode());
341+
}
320342
}

tests/unit/XmlStringStreamer/Parser/UniqueNodeTest.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,4 +263,28 @@ public function test_multiple_roots()
263263
"When no nodes are left, false should be returned"
264264
);
265265
}
266-
}
266+
267+
public function test_orphan_closing_tag_is_ignored()
268+
{
269+
$expectedStringToBeFlushed = '<child>read this</child>';
270+
$xml = <<<eot
271+
<?xml version="1.0"?>
272+
<root>
273+
</child>
274+
$expectedStringToBeFlushed
275+
</root>
276+
eot;
277+
278+
$stream = $this->getStreamMock($xml, strlen($xml));
279+
280+
$parser = new UniqueNode([
281+
"uniqueNode" => "child"
282+
]);
283+
284+
$this->assertEquals(
285+
$expectedStringToBeFlushed,
286+
$parser->getNodeFrom($stream),
287+
"Orphan closing tag must not act as closing tag for first opening tag"
288+
);
289+
}
290+
}

tests/xml/stream_seeking.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<root>
2+
<item>first item to read</item>
3+
<item>seek will land before hash character: #</item>
4+
<item>second item to read</item>
5+
</root>

0 commit comments

Comments
 (0)