From b01f9925e8d2c49cbdf2007c6affb139fa538f03 Mon Sep 17 00:00:00 2001 From: Julian Wundrak Date: Tue, 16 Aug 2022 08:33:36 +0200 Subject: [PATCH 01/12] Support read children without using "skipNextRead" --- src/XMLChildElementIterator.php | 39 +++++++++++++++++++++++++++++++-- src/XMLReaderIterator.php | 8 ++++++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/XMLChildElementIterator.php b/src/XMLChildElementIterator.php index c192063..2974090 100644 --- a/src/XMLChildElementIterator.php +++ b/src/XMLChildElementIterator.php @@ -53,6 +53,11 @@ class XMLChildElementIterator extends XMLElementIterator */ private $name; + /** + * @var int + */ + private $innerDepth; + /** * @inheritdoc * @@ -81,6 +86,11 @@ public function rewind() !$this->moveToNextByNodeType(XMLReader::ELEMENT); } + // handles e.g. -> no children available + if ($this->reader->isEmptyElement) { + return; + } + if ($this->stopDepth === null) { $this->stopDepth = $this->reader->depth; } @@ -89,6 +99,7 @@ public function rewind() $result = $this->nextChildElementByName($this->name); $this->index = $result ? 0 : null; + $this->innerDepth = 1; $this->didRewind = true; } @@ -160,7 +171,7 @@ private function nextChildElementByName($name = null) } } - return (bool)$next; + return $next; } /** @@ -168,7 +179,7 @@ private function nextChildElementByName($name = null) */ private function nextElement() { - while ($this->reader->read()) { + while ($this->readNext()) { if (XMLReader::ELEMENT !== $this->reader->nodeType) { continue; } @@ -177,4 +188,28 @@ private function nextElement() } return false; } + + /** + * Wrap reading to track opening and closing tags to prevent reading not-children nodes + * + * @return bool + */ + protected function readNext() + { + // update inner depth + if ($this->reader->nodeType === XMLReader::ELEMENT && !$this->reader->isEmptyElement) { + $this->innerDepth++; + } elseif ($this->reader->nodeType === XMLReader::END_ELEMENT) { + $this->innerDepth--; + + // all children read? Abort to prevent reading next node + if ($this->innerDepth === 0) { + // set pointer behind closing-tag + parent::readNext(); + return false; + } + } + + return parent::readNext(); + } } diff --git a/src/XMLReaderIterator.php b/src/XMLReaderIterator.php index 4d17045..dbcc019 100644 --- a/src/XMLReaderIterator.php +++ b/src/XMLReaderIterator.php @@ -167,11 +167,17 @@ public function next() if ($this->skipNextRead) { $this->skipNextRead = false; $this->lastRead = $this->reader->nodeType !== XMLReader::NONE; - } elseif ($this->lastRead = $this->reader->read() and $this->reader->nodeType === XMLReader::ELEMENT) { + } elseif ($this->lastRead = $this->readNext() and $this->reader->nodeType === XMLReader::ELEMENT) { $this->touchElementStack(); } } + #[\ReturnTypeWillChange] + protected function readNext() + { + return $this->reader->read(); + } + /** * @return string * @since 0.0.19 From d4138bea1c57f81e9a5257dd9cf29cece11d7857 Mon Sep 17 00:00:00 2001 From: Julian Wundrak Date: Tue, 16 Aug 2022 08:34:00 +0200 Subject: [PATCH 02/12] Provide example and tests --- examples/child-nested-read.php | 19 +++++++ examples/data/products.xml | 52 +++++++++++++++++++ .../Expectations/child-nested-read_php.out | 21 ++++++++ tests/unit/XMLChildElementIteratorTest.php | 23 +++++++- 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 examples/child-nested-read.php create mode 100644 examples/data/products.xml create mode 100644 tests/functional/examples/Expectations/child-nested-read_php.out diff --git a/examples/child-nested-read.php b/examples/child-nested-read.php new file mode 100644 index 0000000..608da19 --- /dev/null +++ b/examples/child-nested-read.php @@ -0,0 +1,19 @@ + $list */ +$iterator = new XMLElementIterator(XMLReader::open($xmlFile)); +$list = new XMLElementXpathFilter($iterator, '//product'); + +foreach ($list as $item) { + printf('Found product "%s"' . \PHP_EOL, $item->getAttribute('sku')); + + foreach ($item->getChildElements('attributes') as $attributeList) { + foreach ($attributeList->getChildElements() as $attribute) { + printf(' - %s: %s' . \PHP_EOL, $attribute->name, (string)$attribute); + } + } +} \ No newline at end of file diff --git a/examples/data/products.xml b/examples/data/products.xml new file mode 100644 index 0000000..d274797 --- /dev/null +++ b/examples/data/products.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + Test product + + + + + Test product in blue + 15.00 + + + + + Test product in red + 12.00 + + + + + + + Simple test product + 10.99 + + + + + Another product + 99.99 + + + + + L + + + + + M + + + + + diff --git a/tests/functional/examples/Expectations/child-nested-read_php.out b/tests/functional/examples/Expectations/child-nested-read_php.out new file mode 100644 index 0000000..e4c07e4 --- /dev/null +++ b/tests/functional/examples/Expectations/child-nested-read_php.out @@ -0,0 +1,21 @@ +Found product "empty_product" +Found product "empty_attributes" +Found product "no_attributes" +Found product "foo" + - name: Test product +Found product "foo_blue" + - name: Test product in blue + - price: 15.00 +Found product "foo_red" + - name: Test product in red + - price: 12.00 +Found product "bar" + - name: Simple test product + - price: 10.99 +Found product "foobar" + - name: Another product + - price: 99.99 +Found product "foobar_l" + - size: L +Found product "foobar_m" + - size: M diff --git a/tests/unit/XMLChildElementIteratorTest.php b/tests/unit/XMLChildElementIteratorTest.php index 26957ed..e4d229a 100644 --- a/tests/unit/XMLChildElementIteratorTest.php +++ b/tests/unit/XMLChildElementIteratorTest.php @@ -91,7 +91,6 @@ public function testIteration() $this->assertEquals($expected[$index], $reader->name); } $this->assertEquals(count($expected), $count); - } /** @@ -142,4 +141,26 @@ public function testDescendantChildren() $array = iterator_to_array($children, false); $this->assertSame(array(), $array, 'all children have been consumed by foreach'); } + + /** + * Test child-iterator without calling 'skipNextRead' method + */ + public function testIterationOnChildrenStopBeforeReadingNextElement() + { + $reader = XMLReader::open(__DIR__ . '/../../examples/data/sample-rss-091.xml'); + $this->assertTrue(!!$reader, 'fixture document can be opened successfully'); + $items = new XMLElementIterator($reader, 'item'); + foreach ($items as $idx => $item) { + $children = $items->getChildElements(); + $children->rewind(); + foreach (array('title', 'link', 'description') as $tagName) { + $this->assertTrue($children->valid()); + $this->assertSame($tagName, $children->name); + $children->next(); + } + $this->assertFalse($children->valid()); + } + $this->assertSame(6, $idx, 'sample-rss-091.xml element has 7 item elements'); + $this->assertEmpty(\iterator_to_array($items), 'all children have been consumed by foreach'); + } } From 212164beaaad87c87724672f2d1316b78016c452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Proch=C3=A1zka?= Date: Wed, 6 Dec 2023 21:00:53 +0100 Subject: [PATCH 03/12] Switch self keyword in callback to class name --- src/XMLBuild.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XMLBuild.php b/src/XMLBuild.php index dce4562..8db197e 100644 --- a/src/XMLBuild.php +++ b/src/XMLBuild.php @@ -100,7 +100,7 @@ public static function attributeValue($value) // REC-xml/#AVNormalize - preserve // REC-xml/#sec-line-ends - preserve - $buffer = preg_replace_callback('~\r\n|\r(?!\n)|\t~', array('self', 'numericEntitiesSingleByte'), $buffer); + $buffer = preg_replace_callback('~\r\n|\r(?!\n)|\t~', array('XMLBuild', 'numericEntitiesSingleByte'), $buffer); return htmlspecialchars($buffer, ENT_QUOTES, 'UTF-8', false); } From 42af9489405c704a851e0aa23ba3d249b7688a90 Mon Sep 17 00:00:00 2001 From: juniwalk Date: Sun, 27 Jul 2025 12:18:22 +0200 Subject: [PATCH 04/12] Explicit nullable type --- src/XMLReaderNode.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XMLReaderNode.php b/src/XMLReaderNode.php index 0ef42e1..6b41206 100644 --- a/src/XMLReaderNode.php +++ b/src/XMLReaderNode.php @@ -212,7 +212,7 @@ public function readOuterXml() * @throws BadMethodCallException * @return DOMNode */ - public function expand(DOMNode $baseNode = null) + public function expand(?DOMNode $baseNode = null) { if (null === $baseNode) { $baseNode = new DomDocument(); From 0ddfcda99637e35de6593cffed49080bacfd8adf Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 1 Sep 2025 00:00:00 +0000 Subject: [PATCH 05/12] Patched vendor automatically on install. --- composer.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 65c6c09..994ead5 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,11 @@ { "name": "hakre/xmlreaderiterator", "description": "Iterators for PHP XMLReader for ease of parsing", - "keywords": ["XML", "XMLReader", "Iterator"], + "keywords": [ + "XML", + "XMLReader", + "Iterator" + ], "homepage": "https://github.com/hakre/XMLReaderIterator", "minimum-stability": "stable", "license": "AGPL-3.0-or-later", @@ -24,5 +28,15 @@ "ext-bz2": "*", "ext-libxml": "*", "phpunit/phpunit": "3.7.*" + }, + "scripts": { + "post-install-cmd": [ + "# For dev, patching phpunit for compatibility with all versions of php. Require php 5.3.3 to php 7.4.", + "[ $COMPOSER_DEV_MODE -eq 0 ] || patch -d vendor -p1 < vendor/vendor-dev.patch" + ], + "post-update-cmd": [ + "# For dev, patching phpunit for compatibility with all versions of php. Require php 5.3.3 to php 7.4.", + "[ $COMPOSER_DEV_MODE -eq 0 ] || patch -d vendor -p1 < vendor/vendor-dev.patch" + ] } } From 585c24831642113c3cf20636e4c3b05287f4e557 Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 1 Sep 2025 00:00:00 +0000 Subject: [PATCH 06/12] Normalized inline docblocks. --- build.php | 2 +- build/include/xmlreader-iterators.php | 8 ++++---- src/DOMReadingIteration.php | 10 +++++----- src/XMLAttributeFilterBase.php | 2 +- src/XMLReaderIterator.php | 2 +- tests/unit/XMLReaderIterationTest.php | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/build.php b/build.php index 314fe2a..cb9a3a2 100644 --- a/build.php +++ b/build.php @@ -561,7 +561,7 @@ function deltree($path) $path = array_pop($stack); $it = new DirectoryIterator($path); foreach ($it as $file) { - /* @var $file DirectoryIterator */ + /** @var DirectoryIterator $file */ if ($file->isDot()) { continue; } diff --git a/build/include/xmlreader-iterators.php b/build/include/xmlreader-iterators.php index 7b104ad..3f13313 100644 --- a/build/include/xmlreader-iterators.php +++ b/build/include/xmlreader-iterators.php @@ -487,7 +487,7 @@ public function getNodeTree() { $stack = $this->elementStack; $buffer = ''; - /* @var $element XMLReaderElement */ + /** @var \XMLReaderElement $element */ while ($element = array_pop($stack)) { $buffer = $element->getXMLElementAround($buffer); } @@ -770,13 +770,13 @@ private function build() case XMLReader::ELEMENT: $parent = $this->stack[$depth]; $prefix = $this->reader->prefix; - /* @var $node DOMElement */ + /** @var \DOMElement $node */ if ($prefix) { $uri = $parent->lookupNamespaceURI($prefix) ?: $this->nsUriSelfLookup($prefix); if ($uri === NULL) { trigger_error(sprintf('Unable to lookup NS URI for element prefix "%s"', $prefix)); } - /* @var $doc DOMDocument */ + /** @var \DOMDocument $doc */ $doc = ($parent->ownerDocument?:$parent); $node = $doc->createElementNS($uri, $this->reader->name); $node = $parent->appendChild($node); @@ -1789,7 +1789,7 @@ public function __construct(XMLElementIterator $elements, $attr) protected function getAttributeValues() { - /* @var $node XMLReaderNode */ + /** @var \XMLReaderNode $node */ $node = parent::current(); if ('*' === $this->attr) { $attributes = $node->getAttributes()->getArrayCopy(); diff --git a/src/DOMReadingIteration.php b/src/DOMReadingIteration.php index d41c311..f8dca07 100644 --- a/src/DOMReadingIteration.php +++ b/src/DOMReadingIteration.php @@ -35,7 +35,7 @@ class DOMReadingIteration extends IteratorIterator const XMLNS = 'xmlns'; /** - * @var array|DOMNode[] + * @var array|\DOMNode[] */ private $stack; @@ -50,12 +50,12 @@ class DOMReadingIteration extends IteratorIterator private $lastDepth; /** - * @var DOMNode + * @var \DOMNode */ private $node; /** - * @var DOMNode + * @var \DOMNode */ private $lastNode; @@ -106,13 +106,13 @@ private function build() case XMLReader::ELEMENT: $parent = $this->stack[$depth]; $prefix = $this->reader->prefix; - /* @var $node DOMElement */ + /** @var \DOMElement $node */ if ($prefix) { $uri = $parent->lookupNamespaceURI($prefix) ?: $this->nsUriSelfLookup($prefix); if ($uri === NULL) { trigger_error(sprintf('Unable to lookup NS URI for element prefix "%s"', $prefix)); } - /* @var $doc DOMDocument */ + /** @var \DOMDocument $doc */ $doc = ($parent->ownerDocument?:$parent); $node = $doc->createElementNS($uri, $this->reader->name); $node = $parent->appendChild($node); diff --git a/src/XMLAttributeFilterBase.php b/src/XMLAttributeFilterBase.php index 4f9d91e..27b17c6 100644 --- a/src/XMLAttributeFilterBase.php +++ b/src/XMLAttributeFilterBase.php @@ -40,7 +40,7 @@ public function __construct(XMLElementIterator $elements, $attr) protected function getAttributeValues() { - /* @var $node XMLReaderNode */ + /** @var \XMLReaderNode $node */ $node = parent::current(); if ('*' === $this->attr) { $attributes = $node->getAttributes()->getArrayCopy(); diff --git a/src/XMLReaderIterator.php b/src/XMLReaderIterator.php index dbcc019..23cdb65 100644 --- a/src/XMLReaderIterator.php +++ b/src/XMLReaderIterator.php @@ -195,7 +195,7 @@ public function getNodeTree() { $stack = $this->elementStack; $buffer = ''; - /* @var $element XMLReaderElement */ + /** @var XMLReaderElement $element */ while ($element = array_pop($stack)) { $buffer = $element->getXMLElementAround($buffer); } diff --git a/tests/unit/XMLReaderIterationTest.php b/tests/unit/XMLReaderIterationTest.php index 953f559..8dad2cf 100644 --- a/tests/unit/XMLReaderIterationTest.php +++ b/tests/unit/XMLReaderIterationTest.php @@ -48,7 +48,7 @@ public function testIteration() $count = 0; - /* @var $reader XMLReader */ + /** @var \XMLReader $reader */ foreach ($iterator as $index => $reader) { $this->assertSame($count, $index); list($nodeType, $depth) = $data[$index]; From 1e76c36d9bb903acad8fe29d55a75f65f522c443 Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 1 Sep 2025 00:00:00 +0000 Subject: [PATCH 07/12] Completed docblocks. --- build.php | 63 +++++++++++----------- build/include/xmlreader-iterators.php | 20 +++---- src/BufferedFileRead.php | 10 ++-- src/BufferedFileReaders.php | 8 +-- src/XMLReaderIteration.php | 2 +- src/XMLSequenceStream.php | 2 +- tests/functional/examples/ExamplesTest.php | 2 +- tests/unit/XMLReaderTestCase.php | 3 +- tests/unit/XMLSequenceStreamTest.php | 2 +- 9 files changed, 57 insertions(+), 55 deletions(-) diff --git a/build.php b/build.php index cb9a3a2..f0f1034 100644 --- a/build.php +++ b/build.php @@ -26,6 +26,10 @@ built_test_git_tag($readmeVersion, $errors); +/** + * @param string $version + * @param int $errors + */ function built_test_git_tag($version, &$errors) { echo "INFO: Validating git tag version:"; @@ -79,7 +83,7 @@ function built_test_git_tag($version, &$errors) } /** - * @param $errors + * @param int $errors * * @return string|null */ @@ -109,6 +113,12 @@ function built_test_readme_get_version(&$errors) return $version; } +/** + * @param string $version + * @param int $errors + * + * @return bool + */ function built_validate_version($version, &$errors) { if (!preg_match('~^\d\.\d+\.\d+$~', $version)) { @@ -120,11 +130,10 @@ function built_validate_version($version, &$errors) return true; } - /** * @see http://php.net/json_decode * - * @param $path + * @param string $path * @param bool $assoc * @param int $depth * @param int $options @@ -137,7 +146,7 @@ function json_decode_file($path, $assoc = false, $depth = 512, $options = 0) } /** - * @param $errors + * @param int $errors */ function built_test_composer_validate_json(&$errors) { @@ -160,17 +169,14 @@ function built_test_composer_validate_json(&$errors) if ($exitCode !== 0) { echo "ERROR: Composer json validation did return exit code $exitCode which is not 0.\n"; $errors++; - return; } echo "INFO: composer.json validation did pass. You might need to review warnings your own.\n"; - - return; } /** - * @param $errors + * @param int $errors */ function build_test_tests(&$errors) { @@ -189,7 +195,6 @@ function build_test_tests(&$errors) if (!preg_match('~^PHPUnit \d\.\d\.\d+ by Sebastian Bergmann\.$~', $versionLine)) { echo "ERROR: Unable to invoke PHPUnit.\n"; $errors++; - return; } @@ -200,25 +205,21 @@ function build_test_tests(&$errors) if ($result === false) { echo "ERROR: Unable to invoke PHPUnit tests.\n"; $errors++; - return; } if ($exitCode !== 0) { echo "ERROR: PHPUnit did return exit code $exitCode which is not 0.\n"; $errors++; - return; } echo "INFO: phpunit testsuite did pass.\n"; - - return; } /** - * @param $errors - * @param $autoLoadFile + * @param int $errors + * @param string $autoLoadFile */ function build_test_autoload_file(&$errors, $autoLoadFile) { @@ -252,7 +253,6 @@ function build_create_concatenate_file(&$errors, $concatenateFile, $autoLoadFile if (!$concatenateFileHandle) { echo "ERROR: concatenateFile '$concatenateFile' can not be created.\n"; $errors++; - return; } } @@ -292,6 +292,7 @@ function build_create_concatenate_file(&$errors, $concatenateFile, $autoLoadFile fclose($handle); $count++; } + printf("INFO: concatenated %d files into %s.\n", $count, cwdname($concatenateFile)); $buffer = file_get_contents($concatenateFile); @@ -321,7 +322,6 @@ function build_create_concatenate_file(&$errors, $concatenateFile, $autoLoadFile return; } - $search = " * @license AGPL-3.0-or-later \n */"; $replace = " * @license AGPL-3.0-or-later \n * @version $version\n */"; @@ -350,9 +350,9 @@ function build_create_concatenate_file(&$errors, $concatenateFile, $autoLoadFile } /** - * @param $errors - * @param $buildDir - * @param $concatenateDir + * @param int $errors + * @param string $buildDir + * @param string $concatenateDir */ function build_make_clean(&$errors, $buildDir, $concatenateDir) { @@ -369,8 +369,10 @@ function build_make_clean(&$errors, $buildDir, $concatenateDir) } /** - * @param $errors - * @param $pathSpec + * @param int $errors + * @param string $workdDir + * @param string $pathSpec + * * @return bool|null on error */ function build_tree_uncommitted_changes(&$errors, $workDir, $pathSpec = '.') @@ -395,9 +397,9 @@ function build_tree_uncommitted_changes(&$errors, $workDir, $pathSpec = '.') } /** - * @param $errors - * @param $gistDir - * @param $readmeVersion + * @param int $errors + * @param string $gistDir + * @param string $readmeVersion */ function build_gist_commit(&$errors, $gistDir, $readmeVersion) { @@ -407,12 +409,13 @@ function build_gist_commit(&$errors, $gistDir, $readmeVersion) if (0 !== $exitCode) { echo "ERROR: git execution in ", __FUNCTION__, "() non-zero exit status.\n"; $errors++; - return null; + return; } if ('' === $readmeVersion) { return; } + $gistCurrentMessage = implode("\n", $output) . "\n"; $target = "Version $readmeVersion\n\n"; $needsAmending = $gistCurrentMessage === $target; @@ -430,7 +433,7 @@ function build_gist_commit(&$errors, $gistDir, $readmeVersion) if (0 !== $exitCode) { echo "ERROR: gist command '$command' non-zero exit status.\n"; $errors++; - return null; + return; } if ($needsAmending) { @@ -453,7 +456,7 @@ function build_gist_commit(&$errors, $gistDir, $readmeVersion) } /** - * @param $handle + * @param resource $handle * * @return bool */ @@ -477,7 +480,7 @@ function fseek_first_empty_line($handle) /** * shorten pathname realtive to cwd * - * @param $path + * @param string $path * * @return string */ @@ -545,7 +548,7 @@ function copy_file_to_dir($file, $targetDir) * implemented as a stack so that no recursion is necessar and * traversal is fast. * - * @param $path + * @param string $path */ function deltree($path) { diff --git a/build/include/xmlreader-iterators.php b/build/include/xmlreader-iterators.php index 3f13313..993da88 100644 --- a/build/include/xmlreader-iterators.php +++ b/build/include/xmlreader-iterators.php @@ -528,7 +528,7 @@ class XMLReaderIteration implements Iterator private $reader; /** - * @var boolean + * @var bool */ private $valid; @@ -1956,8 +1956,8 @@ final class BufferedFileRead private $readAhead = 0; /** - * @param $filename - * @param $mode + * @param string $filename + * @param string $mode * @param null $use_include_path * @param null $context * @@ -1994,7 +1994,7 @@ public function fopen($filename, $mode, $use_include_path = null, $context = nul * appends up to $count bytes to the buffer up to * the read-ahead limit * - * @param $count + * @param int $count * * @return int|bool length of buffer or FALSE on error */ @@ -2026,7 +2026,7 @@ public function append($count) /** * shift bytes from buffer * - * @param $bytes - up to buffer-length bytes + * @param int $bytes - up to buffer-length bytes * * @return string */ @@ -2109,10 +2109,10 @@ class BufferedFileReaders private $readers; /** - * @param $filename - * @param $mode - * @param $use_include_path - * @param $context + * @param string $filename + * @param string $mode + * @param bool $use_include_path + * @param resource|null $context * * @return BufferedFileRead or null on error */ @@ -2286,7 +2286,7 @@ public static function closeBuffer($path) } /** - * @param $path + * @param string $path * * @return bool */ diff --git a/src/BufferedFileRead.php b/src/BufferedFileRead.php index e838df2..ed3685b 100644 --- a/src/BufferedFileRead.php +++ b/src/BufferedFileRead.php @@ -62,10 +62,10 @@ final class BufferedFileRead private $readAhead = 0; /** - * @param $filename - * @param $mode + * @param string $filename + * @param string $mode * @param null $use_include_path - * @param null $context + * @param resource|null $context * * @return bool */ @@ -100,7 +100,7 @@ public function fopen($filename, $mode, $use_include_path = null, $context = nul * appends up to $count bytes to the buffer up to * the read-ahead limit * - * @param $count + * @param int $count * * @return int|bool length of buffer or FALSE on error */ @@ -132,7 +132,7 @@ public function append($count) /** * shift bytes from buffer * - * @param $bytes - up to buffer-length bytes + * @param int $bytes - up to buffer-length bytes * * @return string */ diff --git a/src/BufferedFileReaders.php b/src/BufferedFileReaders.php index eb719b3..d75670a 100644 --- a/src/BufferedFileReaders.php +++ b/src/BufferedFileReaders.php @@ -39,10 +39,10 @@ class BufferedFileReaders private $readers; /** - * @param $filename - * @param $mode - * @param $use_include_path - * @param $context + * @param string $filename + * @param string $mode + * @param bool $use_include_path + * @param resource|null $context * * @return BufferedFileRead or null on error */ diff --git a/src/XMLReaderIteration.php b/src/XMLReaderIteration.php index dc10bf9..8704df9 100644 --- a/src/XMLReaderIteration.php +++ b/src/XMLReaderIteration.php @@ -36,7 +36,7 @@ class XMLReaderIteration implements Iterator private $reader; /** - * @var boolean + * @var bool */ private $valid; diff --git a/src/XMLSequenceStream.php b/src/XMLSequenceStream.php index c128e2a..833a412 100644 --- a/src/XMLSequenceStream.php +++ b/src/XMLSequenceStream.php @@ -86,7 +86,7 @@ public static function closeBuffer($path) } /** - * @param $path + * @param string $path * * @return bool */ diff --git a/tests/functional/examples/ExamplesTest.php b/tests/functional/examples/ExamplesTest.php index 22b25bc..7056300 100644 --- a/tests/functional/examples/ExamplesTest.php +++ b/tests/functional/examples/ExamplesTest.php @@ -39,7 +39,7 @@ protected function tearDown() /** - * @param $file + * @param string $file * * @throws Exception * @throws PHPUnit_Framework_SkippedTest diff --git a/tests/unit/XMLReaderTestCase.php b/tests/unit/XMLReaderTestCase.php index 9d17e5d..4d843c5 100644 --- a/tests/unit/XMLReaderTestCase.php +++ b/tests/unit/XMLReaderTestCase.php @@ -38,12 +38,11 @@ protected function setUp() parent::setUp(); } - /** * helper method to create data-providers * * @param array $result - * @param $path + * @param string $path * * @return array of arrays with one entry of each filename as string */ diff --git a/tests/unit/XMLSequenceStreamTest.php b/tests/unit/XMLSequenceStreamTest.php index 195c39a..a97161c 100644 --- a/tests/unit/XMLSequenceStreamTest.php +++ b/tests/unit/XMLSequenceStreamTest.php @@ -67,7 +67,7 @@ public function testDeclPosPattern($subject) /** * @dataProvider provideStreamFiles * - * @param $file + * @param string $file */ public function testReadStream($file) { From 0ba20aac9e665d2e1e54bd57b4f96a1f5f46b79e Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 1 Sep 2025 00:00:00 +0000 Subject: [PATCH 08/12] Updated .gitignore. --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index e9418d0..c1b07e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,11 @@ build/ vendor/ +.settings/ +.buildpath +.bundle +.cache +.DS_Store +.php_cs.cache +.php-cs-fixer.cache +.phpunit.result.cache +.project From 861083be5107c49c645e0ce19b537276c3c8246f Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 1 Sep 2025 00:00:00 +0000 Subject: [PATCH 09/12] Normalized code. --- README.md | 11 +- build.php | 4 +- build/include/README.md | 11 +- build/include/xmlreader-iterators.php | 170 ++++++++++++++------- examples/child-iterator.php | 2 +- examples/child-nested-read.php | 6 +- examples/element-iterator.php | 4 +- examples/read-into-dom.php | 2 +- examples/read-write-cdata.php | 3 +- examples/read-write-dom.php | 3 +- examples/read-write-simplexml.php | 3 +- examples/read-write.php | 3 +- examples/xml-file-scanner.php | 23 ++- examples/xml-sequence-stream.php | 2 +- examples/xmlreader-iterators.php | 2 +- examples/xmlreader-standard.php | 2 +- examples/xpath.php | 4 +- src/BufferedFileRead.php | 36 +++-- src/DOMReadingIteration.php | 28 ++-- src/XMLAttributeFilter.php | 1 - src/XMLAttributePreg.php | 2 +- src/XMLBuild.php | 3 +- src/XMLNodeTypeFilter.php | 1 - src/XMLReaderFilterBase.php | 4 +- src/XMLReaderIterator.php | 2 - src/XMLReaderNode.php | 5 +- src/XMLSequenceStream.php | 2 +- src/XMLSequenceStreamPath.php | 19 ++- src/XMLWritingIteration.php | 6 +- tests/autoload/test.php | 10 +- tests/bootstrap.php | 6 +- tests/functional/examples/ExamplesTest.php | 10 +- tests/unit/XMLChildElementIteratorTest.php | 4 +- tests/unit/XMLReaderElementTest.php | 9 +- tests/unit/XMLReaderIteratorTest.php | 7 +- 35 files changed, 236 insertions(+), 174 deletions(-) diff --git a/README.md b/README.md index a3dfe1f..906d15b 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ - `0.0.23` first try of a compatibility layer for PHP installs with a libxml version below version 2.6.20. functions with compatibility checks are `XMLReaderNode::readOuterXml()` - and `XMLReaderNode::readString()`. + and `XMLReaderNode::readString()`. - `0.0.21` moved library into new repository and added `XMLReaderAggregate`. @@ -46,7 +46,7 @@ - `0.0.19` added `XMLElementXpathFilter`, a `FilterIterator` for `XMLReaderIterator` by an xpath expression. - ~~~php + ```php $reader = new XMLReader(); $reader->open($xmlFile); $it = new XMLElementIterator($reader); @@ -56,15 +56,14 @@ '//user[@id = "1" or @id = "6"]//message' ); - foreach($list as $message) { + foreach ($list as $message) { echo " * ", $message->readString(), "\n"; } - ~~~ + ``` ### Stackoverflow Q&A for the XMLReader Iterators -the latest on top (for more examples, checkout the -[`examples`] folder): +the latest on top (for more examples, checkout the [`examples`] folder): - [Add Tag Element using XMLReader and SimpleXML or XMLWriter](https://stackoverflow.com/q/69455574/367456) - [How to distinguish between empty element and null-size string in DOMDocument?](http://stackoverflow.com/a/24109776/367456) diff --git a/build.php b/build.php index f0f1034..f92562c 100644 --- a/build.php +++ b/build.php @@ -476,7 +476,6 @@ function fseek_first_empty_line($handle) return !fseek($handle, $lastLine); } - /** * shorten pathname realtive to cwd * @@ -619,10 +618,9 @@ function stream_put_contents($handle, $data, $offset = null, $maxlength = null) return false; } - $length = strlen($data); if (null !== $maxlength) { - $length = max(0, (int)$maxlength); + $length = max(0, (int) $maxlength); } if (null !== $offset) { diff --git a/build/include/README.md b/build/include/README.md index a3dfe1f..906d15b 100644 --- a/build/include/README.md +++ b/build/include/README.md @@ -38,7 +38,7 @@ - `0.0.23` first try of a compatibility layer for PHP installs with a libxml version below version 2.6.20. functions with compatibility checks are `XMLReaderNode::readOuterXml()` - and `XMLReaderNode::readString()`. + and `XMLReaderNode::readString()`. - `0.0.21` moved library into new repository and added `XMLReaderAggregate`. @@ -46,7 +46,7 @@ - `0.0.19` added `XMLElementXpathFilter`, a `FilterIterator` for `XMLReaderIterator` by an xpath expression. - ~~~php + ```php $reader = new XMLReader(); $reader->open($xmlFile); $it = new XMLElementIterator($reader); @@ -56,15 +56,14 @@ '//user[@id = "1" or @id = "6"]//message' ); - foreach($list as $message) { + foreach ($list as $message) { echo " * ", $message->readString(), "\n"; } - ~~~ + ``` ### Stackoverflow Q&A for the XMLReader Iterators -the latest on top (for more examples, checkout the -[`examples`] folder): +the latest on top (for more examples, checkout the [`examples`] folder): - [Add Tag Element using XMLReader and SimpleXML or XMLWriter](https://stackoverflow.com/q/69455574/367456) - [How to distinguish between empty element and null-size string in DOMDocument?](http://stackoverflow.com/a/24109776/367456) diff --git a/build/include/xmlreader-iterators.php b/build/include/xmlreader-iterators.php index 993da88..9f5b4d6 100644 --- a/build/include/xmlreader-iterators.php +++ b/build/include/xmlreader-iterators.php @@ -44,7 +44,6 @@ public function getReader(); */ abstract class XMLBuild { - /** * indentLines() * @@ -114,7 +113,7 @@ public static function attributeValue($value) // REC-xml/#AVNormalize - preserve // REC-xml/#sec-line-ends - preserve - $buffer = preg_replace_callback('~\r\n|\r(?!\n)|\t~', array('self', 'numericEntitiesSingleByte'), $buffer); + $buffer = preg_replace_callback('~\r\n|\r(?!\n)|\t~', array('XMLBuild', 'numericEntitiesSingleByte'), $buffer); return htmlspecialchars($buffer, ENT_QUOTES, 'UTF-8', false); } @@ -166,6 +165,7 @@ public static function readerNode(XMLReader $reader) * * @param string $str * @param int|null $maxLen optional, defaults to 20 (null), 0 (or below) for 512 block size + * * @return string */ public static function displayString($str, $maxLen = null) @@ -188,6 +188,7 @@ public static function displayString($str, $maxLen = null) * * @param string $str * @param int|null $maxLen {@see XMLBuild::displayString()} + * * @return string */ public static function dumpString($str, $maxLen = null) @@ -371,7 +372,6 @@ public function getReader() * compare {@see XMLReaderIteration::skipNextRead()} * * @see XMLReaderIterator::next() - * */ public function skipNextRead() { @@ -386,7 +386,6 @@ public function moveToNextElementByName($name = null) } self::next(); } - ; return self::valid() ? self::current() : false; } @@ -465,11 +464,17 @@ public function next() if ($this->skipNextRead) { $this->skipNextRead = false; $this->lastRead = $this->reader->nodeType !== XMLReader::NONE; - } elseif ($this->lastRead = $this->reader->read() and $this->reader->nodeType === XMLReader::ELEMENT) { + } elseif ($this->lastRead = $this->readNext() and $this->reader->nodeType === XMLReader::ELEMENT) { $this->touchElementStack(); } } + #[\ReturnTypeWillChange] + protected function readNext() + { + return $this->reader->read(); + } + /** * @return string * @since 0.0.19 @@ -487,7 +492,7 @@ public function getNodeTree() { $stack = $this->elementStack; $buffer = ''; - /** @var \XMLReaderElement $element */ + /** @var XMLReaderElement $element */ while ($element = array_pop($stack)) { $buffer = $element->getXMLElementAround($buffer); } @@ -685,7 +690,6 @@ private function moveReaderToCurrent() } } - /** * Class DOMReadingIteration * @@ -699,7 +703,7 @@ class DOMReadingIteration extends IteratorIterator const XMLNS = 'xmlns'; /** - * @var array|DOMNode[] + * @var array|\DOMNode[] */ private $stack; @@ -714,12 +718,12 @@ class DOMReadingIteration extends IteratorIterator private $lastDepth; /** - * @var DOMNode + * @var \DOMNode */ private $node; /** - * @var DOMNode + * @var \DOMNode */ private $lastNode; @@ -756,11 +760,11 @@ public function rewind() private function build() { if (!$this->valid()) { - $this->depth = NULL; - $this->lastDepth = NULL; - $this->node = NULL; - $this->lastNode = NULL; - $this->stack = NULL; + $this->depth = null; + $this->lastDepth = null; + $this->node = null; + $this->lastNode = null; + $this->stack = null; return; } @@ -773,11 +777,11 @@ private function build() /** @var \DOMElement $node */ if ($prefix) { $uri = $parent->lookupNamespaceURI($prefix) ?: $this->nsUriSelfLookup($prefix); - if ($uri === NULL) { + if ($uri === null) { trigger_error(sprintf('Unable to lookup NS URI for element prefix "%s"', $prefix)); } /** @var \DOMDocument $doc */ - $doc = ($parent->ownerDocument?:$parent); + $doc = ($parent->ownerDocument ?: $parent); $node = $doc->createElementNS($uri, $this->reader->name); $node = $parent->appendChild($node); } else { @@ -799,7 +803,7 @@ private function build() $node->setAttributeNS('http://www.w3.org/2000/xmlns/', $this->reader->name, $this->reader->value); } elseif ($prefix) { $uri = $parent->lookupNamespaceUri($prefix) ?: @$nsUris[$prefix]; - if ($uri === NULL) { + if ($uri === null) { trigger_error(sprintf('Unable to lookup NS URI for attribute prefix "%s"', $prefix)); } $node->setAttributeNS($uri, $this->reader->name, $this->reader->value); @@ -811,7 +815,7 @@ private function build() break; case XMLReader::END_ELEMENT: - $node = NULL; + $node = null; break; case XMLReader::COMMENT: @@ -829,8 +833,8 @@ private function build() break; default: - $node = NULL; - $message = sprintf('Unhandled XMLReader node type %s', XMLReaderNode::dump($this->reader, TRUE)); + $node = null; + $message = sprintf('Unhandled XMLReader node type %s', XMLReaderNode::dump($this->reader, true)); trigger_error($message); } @@ -838,8 +842,9 @@ private function build() $this->node = $node; } - private function nsUriSelfLookup($prefix) { - $uri = NULL; + private function nsUriSelfLookup($prefix) + { + $uri = null; if ($this->reader->moveToFirstAttribute()) { do { @@ -892,14 +897,16 @@ class XMLWritingIteration extends IteratorIterator */ private $reader; - public function __construct(XMLWriter $writer, XMLReader $reader) { + public function __construct(XMLWriter $writer, XMLReader $reader) + { $this->writer = $writer; $this->reader = $reader; parent::__construct(new XMLReaderIteration($reader)); } - public function write() { + public function write() + { $reader = $this->reader; $writer = $this->writer; @@ -1142,7 +1149,7 @@ public function readOuterXml() * @throws BadMethodCallException * @return DOMNode */ - public function expand(DOMNode $baseNode = null) + public function expand(?DOMNode $baseNode = null) { if (null === $baseNode) { $baseNode = new DomDocument(); @@ -1280,7 +1287,7 @@ public function __isset($name) * @param bool $return (optional) prints by default but can return string * @return string|void */ - public static function dump(XMLReader $reader, $return = FALSE) + public static function dump(XMLReader $reader, $return = false) { $node = new self($reader); @@ -1302,13 +1309,12 @@ public static function dump(XMLReader $reader, $return = FALSE) $extra = sprintf(' %s = %s', $reader->name, XMLBuild::dumpString($reader->value)); } - if ($reader->nodeType === XMLReader::CDATA || $reader->nodeType === XMLReader::TEXT || $reader->nodeType === XMLReader::WHITESPACE || $reader->nodeType === XMLReader::SIGNIFICANT_WHITESPACE ) { - $extra = sprintf( ' %s', XMLBuild::dumpString($reader->value)); + $extra = sprintf(' %s', XMLBuild::dumpString($reader->value)); } $label = sprintf("(#%d) %s%s", $nodeType, $nodeName, $extra); @@ -1582,6 +1588,11 @@ class XMLChildElementIterator extends XMLElementIterator */ private $name; + /** + * @var int + */ + private $innerDepth; + /** * @inheritdoc * @@ -1610,6 +1621,11 @@ public function rewind() !$this->moveToNextByNodeType(XMLReader::ELEMENT); } + // handles e.g. -> no children available + if ($this->reader->isEmptyElement) { + return; + } + if ($this->stopDepth === null) { $this->stopDepth = $this->reader->depth; } @@ -1618,6 +1634,7 @@ public function rewind() $result = $this->nextChildElementByName($this->name); $this->index = $result ? 0 : null; + $this->innerDepth = 1; $this->didRewind = true; } @@ -1689,7 +1706,7 @@ private function nextChildElementByName($name = null) } } - return (bool)$next; + return $next; } /** @@ -1697,7 +1714,7 @@ private function nextChildElementByName($name = null) */ private function nextElement() { - while ($this->reader->read()) { + while ($this->readNext()) { if (XMLReader::ELEMENT !== $this->reader->nodeType) { continue; } @@ -1706,6 +1723,30 @@ private function nextElement() } return false; } + + /** + * Wrap reading to track opening and closing tags to prevent reading not-children nodes + * + * @return bool + */ + protected function readNext() + { + // update inner depth + if ($this->reader->nodeType === XMLReader::ELEMENT && !$this->reader->isEmptyElement) { + $this->innerDepth++; + } elseif ($this->reader->nodeType === XMLReader::END_ELEMENT) { + $this->innerDepth--; + + // all children read? Abort to prevent reading next node + if ($this->innerDepth === 0) { + // set pointer behind closing-tag + parent::readNext(); + return false; + } + } + + return parent::readNext(); + } } /** @@ -1717,8 +1758,8 @@ private function nextElement() */ abstract class XMLReaderFilterBase extends FilterIterator implements XMLReaderAggregate { - - public function __construct(XMLReaderIterator $elements) { + public function __construct(XMLReaderIterator $elements) + { parent::__construct($elements); } @@ -1735,7 +1776,6 @@ public function getReader() * Class XMLTypeFilter * * FilterIterator to only accept one or more specific XMLReader nodeTypes - * */ class XMLNodeTypeFilter extends XMLReaderFilterBase { @@ -1819,7 +1859,6 @@ class XMLAttributeFilter extends XMLAttributeFilterBase */ public function __construct(XMLElementIterator $elements, $attr, $compare, $invert = false) { - parent::__construct($elements, $attr); $this->compare = (array) $compare; @@ -1867,7 +1906,7 @@ public function __construct(XMLElementIterator $elements, $attr, $pattern, $inve { parent::__construct($elements, $attr); - if (false === preg_match((string)$pattern, '')) { + if (false === preg_match((string) $pattern, '')) { throw new InvalidArgumentException("Invalid pcre pattern '$pattern'."); } $this->pattern = $pattern; @@ -1959,12 +1998,12 @@ final class BufferedFileRead * @param string $filename * @param string $mode * @param null $use_include_path - * @param null $context + * @param resource|null $context * * @return bool */ - public function fopen($filename, $mode, $use_include_path = null, $context = null) { - + public function fopen($filename, $mode, $use_include_path = null, $context = null) + { if ($mode !== self::MODE_READ_BINARY) { $message = sprintf( "unsupported mode '%s', only '%s' is supported for buffered file read", $mode, self::MODE_READ_BINARY @@ -1975,9 +2014,9 @@ public function fopen($filename, $mode, $use_include_path = null, $context = nul } if ($context === null) { - $handle = fopen($filename, self::MODE_READ_BINARY, (bool)$use_include_path); + $handle = fopen($filename, self::MODE_READ_BINARY, (bool) $use_include_path); } else { - $handle = fopen($filename, self::MODE_READ_BINARY, (bool)$use_include_path, $context); + $handle = fopen($filename, self::MODE_READ_BINARY, (bool) $use_include_path, $context); } if (!$handle) { @@ -1996,7 +2035,7 @@ public function fopen($filename, $mode, $use_include_path = null, $context = nul * * @param int $count * - * @return int|bool length of buffer or FALSE on error + * @return int|bool length of buffer or false on error */ public function append($count) { @@ -2045,40 +2084,47 @@ public function shift($bytes) return $return; } - public function fread($count) { + public function fread($count) + { return fread($this->handle, $count); } - public function feof() { + public function feof() + { return feof($this->handle); } /** * @return string */ - public function getFile() { + public function getFile() + { return $this->file; } - public function __toString() { + public function __toString() + { return $this->file; } /** * @return int */ - public function getReadAhead() { + public function getReadAhead() + { return $this->readAhead; } /** * @param int $readAhead */ - public function setReadAhead($readAhead) { - $this->readAhead = max(0, (int)$readAhead); + public function setReadAhead($readAhead) + { + $this->readAhead = max(0, (int) $readAhead); } - public function close() { + public function close() + { if ($this->handle && fclose($this->handle)) { $this->handle = null; } @@ -2086,7 +2132,8 @@ public function close() { $this->buffer = ''; } - public function __destruct() { + public function __destruct() + { $this->close(); } } @@ -2185,28 +2232,32 @@ class XMLSequenceStreamPath */ private $path; - public function __construct($path) { + public function __construct($path) + { $this->path = $path; } - public function getProtocol() { + public function getProtocol() + { $parts = $this->parsePath($this->path); return $parts['scheme']; } - public function getSpecific() { + public function getSpecific() + { $parts = $this->parsePath($this->path); return $parts['specific']; } - public function getFile() { + public function getFile() + { $specific = $this->getSpecific(); $specific = str_replace(array('\\', '/./'), '/', $specific); return $specific; } - private function parsePath($path) { - + private function parsePath($path) + { $parts = array_combine(array('scheme', 'specific'), explode('://', $path, 2) + array(null, null)); if (null === $parts['specific']) { @@ -2216,7 +2267,8 @@ private function parsePath($path) { return $parts; } - public function __toString() { + public function __toString() + { return $this->path; } } @@ -2403,7 +2455,7 @@ public function stream_read($count) private function declPos($offset = 0) { $result = preg_match(self::DECL_POS_PATTERN, $this->reader->buffer, $matches, PREG_OFFSET_CAPTURE, $offset); - if ($result === FALSE) { + if ($result === false) { throw new UnexpectedValueException('Regex failed.'); } diff --git a/examples/child-iterator.php b/examples/child-iterator.php index 09a7de6..d6afb3f 100644 --- a/examples/child-iterator.php +++ b/examples/child-iterator.php @@ -7,7 +7,7 @@ * Example: Iterate over all elements */ -require('xmlreader-iterators.php'); // require XMLReaderIterator library +require 'xmlreader-iterators.php'; // require XMLReaderIterator library $xmlFile = 'data/sample-rss-091.xml'; diff --git a/examples/child-nested-read.php b/examples/child-nested-read.php index 608da19..64293a1 100644 --- a/examples/child-nested-read.php +++ b/examples/child-nested-read.php @@ -1,6 +1,6 @@ getChildElements('attributes') as $attributeList) { foreach ($attributeList->getChildElements() as $attribute) { - printf(' - %s: %s' . \PHP_EOL, $attribute->name, (string)$attribute); + printf(' - %s: %s' . \PHP_EOL, $attribute->name, (string) $attribute); } } -} \ No newline at end of file +} diff --git a/examples/element-iterator.php b/examples/element-iterator.php index 25b643b..d12db54 100644 --- a/examples/element-iterator.php +++ b/examples/element-iterator.php @@ -7,7 +7,7 @@ * Example: Iterate over all elements */ -require('xmlreader-iterators.php'); // require XMLReaderIterator library +require 'xmlreader-iterators.php'; // require XMLReaderIterator library $xmlFile = 'data/movies.xml'; @@ -17,6 +17,6 @@ /** @var XMLElementIterator|XMLReaderNode[] $it */ $it = new XMLElementIterator($reader); -foreach($it as $index => $element) { +foreach ($it as $index => $element) { printf("#%02d: %s\n", $index, XMLBuild::readerNode($reader)); } diff --git a/examples/read-into-dom.php b/examples/read-into-dom.php index 0dce047..f8e698c 100644 --- a/examples/read-into-dom.php +++ b/examples/read-into-dom.php @@ -7,7 +7,7 @@ * Example: Build a DOMDocument with DOMReadingIteration */ -require('xmlreader-iterators.php'); // require XMLReaderIterator library +require 'xmlreader-iterators.php'; // require XMLReaderIterator library $xmlFile = 'data/features-basic.xml'; diff --git a/examples/read-write-cdata.php b/examples/read-write-cdata.php index b44a0c6..20ff694 100644 --- a/examples/read-write-cdata.php +++ b/examples/read-write-cdata.php @@ -9,7 +9,7 @@ * XMLWriter. */ -require('xmlreader-iterators.php'); // require XMLReaderIterator library +require 'xmlreader-iterators.php'; // require XMLReaderIterator library $xmlInputFile = 'data/offers.xml'; $xmlOutputFile = 'php://output'; @@ -35,4 +35,3 @@ } $writer->endDocument(); - diff --git a/examples/read-write-dom.php b/examples/read-write-dom.php index c88476c..50666f7 100644 --- a/examples/read-write-dom.php +++ b/examples/read-write-dom.php @@ -9,7 +9,7 @@ * DOMDocument. */ -require('xmlreader-iterators.php'); // require XMLReaderIterator library +require 'xmlreader-iterators.php'; // require XMLReaderIterator library $xmlInputFile = 'data/offers.xml'; $xmlOutputFile = 'php://output'; @@ -42,4 +42,3 @@ } $writer->endDocument(); - diff --git a/examples/read-write-simplexml.php b/examples/read-write-simplexml.php index 8d969be..e8d55d5 100644 --- a/examples/read-write-simplexml.php +++ b/examples/read-write-simplexml.php @@ -9,7 +9,7 @@ * SimpleXMLElement. */ -require('xmlreader-iterators.php'); // require XMLReaderIterator library +require 'xmlreader-iterators.php'; // require XMLReaderIterator library $xmlInputFile = 'data/offers.xml'; $xmlOutputFile = 'php://output'; @@ -41,4 +41,3 @@ } $writer->endDocument(); - diff --git a/examples/read-write.php b/examples/read-write.php index 2cdb7c7..16f6ee5 100644 --- a/examples/read-write.php +++ b/examples/read-write.php @@ -8,7 +8,7 @@ * XMLWriterIteration; insert new attributes. */ -require('xmlreader-iterators.php'); // require XMLReaderIterator library +require 'xmlreader-iterators.php'; // require XMLReaderIterator library $xmlInputFile = 'data/dobs-items.xml'; $xmlOutputFile = 'php://output'; @@ -28,7 +28,6 @@ foreach ($iterator as $node) { $isElement = $node->nodeType === XMLReader::ELEMENT; - if ($isElement && $node->name === 'ITEMS') { // increase counter for elements and reset counter $itemsCount++; diff --git a/examples/xml-file-scanner.php b/examples/xml-file-scanner.php index 65eec3e..8a9cac6 100644 --- a/examples/xml-file-scanner.php +++ b/examples/xml-file-scanner.php @@ -27,7 +27,7 @@ * Note: use as PHP CLI command */ -require('xmlreader-iterators.php'); // require XMLReaderIterator library +require 'xmlreader-iterators.php'; // require XMLReaderIterator library stream_wrapper_register('xmlseq', 'XMLSequenceStream'); @@ -69,21 +69,21 @@ function print_usage() exit(0); } elseif ($cmd === '-t') { $in = array_shift($process); - if ($in !== trim((int)$in) || $in < 0) { + if ($in !== trim((int) $in) || $in < 0) { echo "invalid -t time limit in seconds: $in\n"; print_usage(); exit(1); } - $timeLimit = (int)$in; + $timeLimit = (int) $in; continue; } elseif ($cmd === '-l') { $in = array_shift($process); - if ($in !== trim((int)$in) || $in < 0) { + if ($in !== trim((int) $in) || $in < 0) { echo "invalid -l elements to scan limit: $in\n"; print_usage(); exit(1); } - $elementsToScan = (int)$in; + $elementsToScan = (int) $in; continue; } elseif ($cmd === '-o') { $in = array_shift($process); @@ -97,19 +97,18 @@ function print_usage() } $file = $cmd; break; -}; - +} -$timeLimit = (int)max(0, $timeLimit); +$timeLimit = (int) max(0, $timeLimit); printf("input.: %s\n", $file); printf("output: %s\n", $outfile); printf( - "limits: %s elements with %s time-limit\n", $elementsToScan ? : 'all', $timeLimit ? "$timeLimit seconds" : 'no' + "limits: %s elements with %s time-limit\n", $elementsToScan ?: 'all', $timeLimit ? "$timeLimit seconds" : 'no' ); -$indexLimit = (int)max(0, $elementsToScan - 2); +$indexLimit = (int) max(0, $elementsToScan - 2); $levels = array(); @@ -270,7 +269,7 @@ public function rewind() #[\ReturnTypeWillChange] public function valid() { - return (bool)$this->toConsume; + return (bool) $this->toConsume; } #[\ReturnTypeWillChange] @@ -305,7 +304,7 @@ public function hasChildren() $this->childCachePrefix = $key; $this->childCache = $this->levels->getChildrenOfAtLevel($key, $this->level + 1); - return (bool)$this->childCache; + return (bool) $this->childCache; } #[\ReturnTypeWillChange] diff --git a/examples/xml-sequence-stream.php b/examples/xml-sequence-stream.php index 8c33013..e490364 100644 --- a/examples/xml-sequence-stream.php +++ b/examples/xml-sequence-stream.php @@ -7,7 +7,7 @@ * Example: Read XML from a file that contains a sequence of XML documents */ -require('xmlreader-iterators.php'); // require XMLReaderIterator library +require 'xmlreader-iterators.php'; // require XMLReaderIterator library stream_wrapper_register('xmlseq', 'XMLSequenceStream'); diff --git a/examples/xmlreader-iterators.php b/examples/xmlreader-iterators.php index 6c76941..52f7329 100644 --- a/examples/xmlreader-iterators.php +++ b/examples/xmlreader-iterators.php @@ -7,4 +7,4 @@ * Only a stub to include the XMLReaderIterator library in the examples. */ -require_once(__DIR__ . '/../autoload.php'); // require XMLReaderIterator library from sources +require_once __DIR__ . '/../autoload.php'; // require XMLReaderIterator library from sources diff --git a/examples/xmlreader-standard.php b/examples/xmlreader-standard.php index 8ffccae..70152fb 100644 --- a/examples/xmlreader-standard.php +++ b/examples/xmlreader-standard.php @@ -7,7 +7,7 @@ * Example: XML Reader standard iteration */ -require('xmlreader-iterators.php'); // require XMLReaderIterator library +require 'xmlreader-iterators.php'; // require XMLReaderIterator library $xml = << diff --git a/examples/xpath.php b/examples/xpath.php index 275107e..19100d7 100644 --- a/examples/xpath.php +++ b/examples/xpath.php @@ -7,7 +7,7 @@ * Example: Filter XML elements by xpath expression */ -require('xmlreader-iterators.php'); // require XMLReaderIterator library +require 'xmlreader-iterators.php'; // require XMLReaderIterator library $xmlFile = 'data/posts.xml'; @@ -20,6 +20,6 @@ /** @var XMLElementXpathFilter|XMLReaderNode[] $list */ $list = new XMLElementXpathFilter($it, '//user[@id = "1" or @id = "6"]//message'); -foreach($list as $message) { +foreach ($list as $message) { echo " * ", $message->readString(), "\n"; } diff --git a/src/BufferedFileRead.php b/src/BufferedFileRead.php index ed3685b..bd90070 100644 --- a/src/BufferedFileRead.php +++ b/src/BufferedFileRead.php @@ -69,8 +69,8 @@ final class BufferedFileRead * * @return bool */ - public function fopen($filename, $mode, $use_include_path = null, $context = null) { - + public function fopen($filename, $mode, $use_include_path = null, $context = null) + { if ($mode !== self::MODE_READ_BINARY) { $message = sprintf( "unsupported mode '%s', only '%s' is supported for buffered file read", $mode, self::MODE_READ_BINARY @@ -81,9 +81,9 @@ public function fopen($filename, $mode, $use_include_path = null, $context = nul } if ($context === null) { - $handle = fopen($filename, self::MODE_READ_BINARY, (bool)$use_include_path); + $handle = fopen($filename, self::MODE_READ_BINARY, (bool) $use_include_path); } else { - $handle = fopen($filename, self::MODE_READ_BINARY, (bool)$use_include_path, $context); + $handle = fopen($filename, self::MODE_READ_BINARY, (bool) $use_include_path, $context); } if (!$handle) { @@ -102,7 +102,7 @@ public function fopen($filename, $mode, $use_include_path = null, $context = nul * * @param int $count * - * @return int|bool length of buffer or FALSE on error + * @return int|bool length of buffer or false on error */ public function append($count) { @@ -151,40 +151,47 @@ public function shift($bytes) return $return; } - public function fread($count) { + public function fread($count) + { return fread($this->handle, $count); } - public function feof() { + public function feof() + { return feof($this->handle); } /** * @return string */ - public function getFile() { + public function getFile() + { return $this->file; } - public function __toString() { + public function __toString() + { return $this->file; } /** * @return int */ - public function getReadAhead() { + public function getReadAhead() + { return $this->readAhead; } /** * @param int $readAhead */ - public function setReadAhead($readAhead) { - $this->readAhead = max(0, (int)$readAhead); + public function setReadAhead($readAhead) + { + $this->readAhead = max(0, (int) $readAhead); } - public function close() { + public function close() + { if ($this->handle && fclose($this->handle)) { $this->handle = null; } @@ -192,7 +199,8 @@ public function close() { $this->buffer = ''; } - public function __destruct() { + public function __destruct() + { $this->close(); } } diff --git a/src/DOMReadingIteration.php b/src/DOMReadingIteration.php index f8dca07..0f12d77 100644 --- a/src/DOMReadingIteration.php +++ b/src/DOMReadingIteration.php @@ -21,7 +21,6 @@ * @license AGPL-3.0-or-later */ - /** * Class DOMReadingIteration * @@ -92,11 +91,11 @@ public function rewind() private function build() { if (!$this->valid()) { - $this->depth = NULL; - $this->lastDepth = NULL; - $this->node = NULL; - $this->lastNode = NULL; - $this->stack = NULL; + $this->depth = null; + $this->lastDepth = null; + $this->node = null; + $this->lastNode = null; + $this->stack = null; return; } @@ -109,11 +108,11 @@ private function build() /** @var \DOMElement $node */ if ($prefix) { $uri = $parent->lookupNamespaceURI($prefix) ?: $this->nsUriSelfLookup($prefix); - if ($uri === NULL) { + if ($uri === null) { trigger_error(sprintf('Unable to lookup NS URI for element prefix "%s"', $prefix)); } /** @var \DOMDocument $doc */ - $doc = ($parent->ownerDocument?:$parent); + $doc = ($parent->ownerDocument ?: $parent); $node = $doc->createElementNS($uri, $this->reader->name); $node = $parent->appendChild($node); } else { @@ -135,7 +134,7 @@ private function build() $node->setAttributeNS('http://www.w3.org/2000/xmlns/', $this->reader->name, $this->reader->value); } elseif ($prefix) { $uri = $parent->lookupNamespaceUri($prefix) ?: @$nsUris[$prefix]; - if ($uri === NULL) { + if ($uri === null) { trigger_error(sprintf('Unable to lookup NS URI for attribute prefix "%s"', $prefix)); } $node->setAttributeNS($uri, $this->reader->name, $this->reader->value); @@ -147,7 +146,7 @@ private function build() break; case XMLReader::END_ELEMENT: - $node = NULL; + $node = null; break; case XMLReader::COMMENT: @@ -165,8 +164,8 @@ private function build() break; default: - $node = NULL; - $message = sprintf('Unhandled XMLReader node type %s', XMLReaderNode::dump($this->reader, TRUE)); + $node = null; + $message = sprintf('Unhandled XMLReader node type %s', XMLReaderNode::dump($this->reader, true)); trigger_error($message); } @@ -174,8 +173,9 @@ private function build() $this->node = $node; } - private function nsUriSelfLookup($prefix) { - $uri = NULL; + private function nsUriSelfLookup($prefix) + { + $uri = null; if ($this->reader->moveToFirstAttribute()) { do { diff --git a/src/XMLAttributeFilter.php b/src/XMLAttributeFilter.php index 1734de2..4357b92 100644 --- a/src/XMLAttributeFilter.php +++ b/src/XMLAttributeFilter.php @@ -39,7 +39,6 @@ class XMLAttributeFilter extends XMLAttributeFilterBase */ public function __construct(XMLElementIterator $elements, $attr, $compare, $invert = false) { - parent::__construct($elements, $attr); $this->compare = (array) $compare; diff --git a/src/XMLAttributePreg.php b/src/XMLAttributePreg.php index bd95bc3..a861c80 100644 --- a/src/XMLAttributePreg.php +++ b/src/XMLAttributePreg.php @@ -42,7 +42,7 @@ public function __construct(XMLElementIterator $elements, $attr, $pattern, $inve { parent::__construct($elements, $attr); - if (false === preg_match((string)$pattern, '')) { + if (false === preg_match((string) $pattern, '')) { throw new InvalidArgumentException("Invalid pcre pattern '$pattern'."); } $this->pattern = $pattern; diff --git a/src/XMLBuild.php b/src/XMLBuild.php index 8db197e..03edd59 100644 --- a/src/XMLBuild.php +++ b/src/XMLBuild.php @@ -30,7 +30,6 @@ */ abstract class XMLBuild { - /** * indentLines() * @@ -152,6 +151,7 @@ public static function readerNode(XMLReader $reader) * * @param string $str * @param int|null $maxLen optional, defaults to 20 (null), 0 (or below) for 512 block size + * * @return string */ public static function displayString($str, $maxLen = null) @@ -174,6 +174,7 @@ public static function displayString($str, $maxLen = null) * * @param string $str * @param int|null $maxLen {@see XMLBuild::displayString()} + * * @return string */ public static function dumpString($str, $maxLen = null) diff --git a/src/XMLNodeTypeFilter.php b/src/XMLNodeTypeFilter.php index 13e4fc9..e7f8805 100644 --- a/src/XMLNodeTypeFilter.php +++ b/src/XMLNodeTypeFilter.php @@ -25,7 +25,6 @@ * Class XMLTypeFilter * * FilterIterator to only accept one or more specific XMLReader nodeTypes - * */ class XMLNodeTypeFilter extends XMLReaderFilterBase { diff --git a/src/XMLReaderFilterBase.php b/src/XMLReaderFilterBase.php index 2e2a4ec..164d42d 100644 --- a/src/XMLReaderFilterBase.php +++ b/src/XMLReaderFilterBase.php @@ -30,8 +30,8 @@ */ abstract class XMLReaderFilterBase extends FilterIterator implements XMLReaderAggregate { - - public function __construct(XMLReaderIterator $elements) { + public function __construct(XMLReaderIterator $elements) + { parent::__construct($elements); } diff --git a/src/XMLReaderIterator.php b/src/XMLReaderIterator.php index 23cdb65..a3ffdb5 100644 --- a/src/XMLReaderIterator.php +++ b/src/XMLReaderIterator.php @@ -73,7 +73,6 @@ public function getReader() * compare {@see XMLReaderIteration::skipNextRead()} * * @see XMLReaderIterator::next() - * */ public function skipNextRead() { @@ -88,7 +87,6 @@ public function moveToNextElementByName($name = null) } self::next(); } - ; return self::valid() ? self::current() : false; } diff --git a/src/XMLReaderNode.php b/src/XMLReaderNode.php index 6b41206..91b6bd7 100644 --- a/src/XMLReaderNode.php +++ b/src/XMLReaderNode.php @@ -350,7 +350,7 @@ public function __isset($name) * @param bool $return (optional) prints by default but can return string * @return string|void */ - public static function dump(XMLReader $reader, $return = FALSE) + public static function dump(XMLReader $reader, $return = false) { $node = new self($reader); @@ -372,13 +372,12 @@ public static function dump(XMLReader $reader, $return = FALSE) $extra = sprintf(' %s = %s', $reader->name, XMLBuild::dumpString($reader->value)); } - if ($reader->nodeType === XMLReader::CDATA || $reader->nodeType === XMLReader::TEXT || $reader->nodeType === XMLReader::WHITESPACE || $reader->nodeType === XMLReader::SIGNIFICANT_WHITESPACE ) { - $extra = sprintf( ' %s', XMLBuild::dumpString($reader->value)); + $extra = sprintf(' %s', XMLBuild::dumpString($reader->value)); } $label = sprintf("(#%d) %s%s", $nodeType, $nodeName, $extra); diff --git a/src/XMLSequenceStream.php b/src/XMLSequenceStream.php index 833a412..b482cdf 100644 --- a/src/XMLSequenceStream.php +++ b/src/XMLSequenceStream.php @@ -203,7 +203,7 @@ public function stream_read($count) private function declPos($offset = 0) { $result = preg_match(self::DECL_POS_PATTERN, $this->reader->buffer, $matches, PREG_OFFSET_CAPTURE, $offset); - if ($result === FALSE) { + if ($result === false) { throw new UnexpectedValueException('Regex failed.'); } diff --git a/src/XMLSequenceStreamPath.php b/src/XMLSequenceStreamPath.php index aa1726a..9887e15 100644 --- a/src/XMLSequenceStreamPath.php +++ b/src/XMLSequenceStreamPath.php @@ -33,28 +33,32 @@ class XMLSequenceStreamPath */ private $path; - public function __construct($path) { + public function __construct($path) + { $this->path = $path; } - public function getProtocol() { + public function getProtocol() + { $parts = $this->parsePath($this->path); return $parts['scheme']; } - public function getSpecific() { + public function getSpecific() + { $parts = $this->parsePath($this->path); return $parts['specific']; } - public function getFile() { + public function getFile() + { $specific = $this->getSpecific(); $specific = str_replace(array('\\', '/./'), '/', $specific); return $specific; } - private function parsePath($path) { - + private function parsePath($path) + { $parts = array_combine(array('scheme', 'specific'), explode('://', $path, 2) + array(null, null)); if (null === $parts['specific']) { @@ -64,7 +68,8 @@ private function parsePath($path) { return $parts; } - public function __toString() { + public function __toString() + { return $this->path; } } diff --git a/src/XMLWritingIteration.php b/src/XMLWritingIteration.php index ee83afc..2ad87e6 100644 --- a/src/XMLWritingIteration.php +++ b/src/XMLWritingIteration.php @@ -41,14 +41,16 @@ class XMLWritingIteration extends IteratorIterator */ private $reader; - public function __construct(XMLWriter $writer, XMLReader $reader) { + public function __construct(XMLWriter $writer, XMLReader $reader) + { $this->writer = $writer; $this->reader = $reader; parent::__construct(new XMLReaderIteration($reader)); } - public function write() { + public function write() + { $reader = $this->reader; $writer = $this->writer; diff --git a/tests/autoload/test.php b/tests/autoload/test.php index af5c174..89025bc 100644 --- a/tests/autoload/test.php +++ b/tests/autoload/test.php @@ -21,7 +21,7 @@ ini_set('log_errors', '1'); ini_set('error_log', ''); ini_set('display_errors', '0'); - ini_set('error_reporting', (string)~0); + ini_set('error_reporting', (string) ~0); } $help = false; @@ -55,7 +55,8 @@ // acquire project class-names by glob pattern $requiredClassNames = array_reduce(glob('src/*.php'), function (array $c, $p) { - $c[] = basename($p, '.php'); return $c; + $c[] = basename($p, '.php'); + return $c; }, array()); if (empty($requiredClassNames)) { fprintf(STDERR, "fatal: no classes to check.\n"); @@ -63,7 +64,7 @@ } // error handling incl. on shutdown to highlight last error if not yet reported -$phpErrors = (object)array('total' => 0, 'by_number' => array(), 'errors' => array(), 'report_on_shutdown' => true); +$phpErrors = (object) array('total' => 0, 'by_number' => array(), 'errors' => array(), 'report_on_shutdown' => true); function error_handler($no, $str, $file, $line) { global $phpErrors; @@ -73,6 +74,7 @@ function error_handler($no, $str, $file, $line) $phpErrors->errors[] = $error; return false; } + function shutdown_function() { global $phpErrors, $label; @@ -96,7 +98,7 @@ function shutdown_function() * test: 1. the require-file can be required */ -$requireResult = require_once($require); +$requireResult = require_once $require; $phpErrors->report_on_shutdown = false; if ($phpErrors->total) { fprintf(STDERR, "fatal: php %s with \"%s\" %d type(s) of error(s) ([%s]), %d total error(s) for require of file: \"%s\".\n", PHP_VERSION, $label, count($phpErrors->by_number), implode('], [', array_keys($phpErrors->by_number)), $phpErrors->total, $require); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index e9ab9b3..c90bbb7 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -7,7 +7,7 @@ * bootstrap for tests */ -require_once(__DIR__ . '/../autoload.php'); +require_once __DIR__ . '/../autoload.php'; -require_once(__DIR__ . '/unit/XMLReaderStub.php'); -require_once(__DIR__ . '/unit/XMLReaderTestCase.php'); +require_once __DIR__ . '/unit/XMLReaderStub.php'; +require_once __DIR__ . '/unit/XMLReaderTestCase.php'; diff --git a/tests/functional/examples/ExamplesTest.php b/tests/functional/examples/ExamplesTest.php index 7056300..a49cc46 100644 --- a/tests/functional/examples/ExamplesTest.php +++ b/tests/functional/examples/ExamplesTest.php @@ -37,7 +37,6 @@ protected function tearDown() parent::tearDown(); } - /** * @param string $file * @@ -46,7 +45,8 @@ protected function tearDown() * * @dataProvider provideExampleFiles */ - public function testRunPhpFile($file) { + public function testRunPhpFile($file) + { $name = basename($file, '.php'); $buffer = null; @@ -86,11 +86,13 @@ public function testRunPhpFile($file) { } } - private function saveInclude() { + private function saveInclude() + { include func_get_arg(0); } - private function getExpectedFile($forFile) { + private function getExpectedFile($forFile) + { $name = basename($forFile); $name = strtr($name, '.', '_'); $file = __DIR__ . '/Expectations/' . $name . '.out'; diff --git a/tests/unit/XMLChildElementIteratorTest.php b/tests/unit/XMLChildElementIteratorTest.php index e4d229a..565235f 100644 --- a/tests/unit/XMLChildElementIteratorTest.php +++ b/tests/unit/XMLChildElementIteratorTest.php @@ -73,7 +73,7 @@ public function testIteration() $this->assertEquals('root', $root->getName()); $count = 0; - foreach($root->getChildElements() as $index => $child) { + foreach ($root->getChildElements() as $index => $child) { $this->assertSame($count++, $index); $this->assertEquals($expected[$index], $reader->name); } @@ -86,7 +86,7 @@ public function testIteration() $this->assertEquals('root', $root->getName()); $count = 0; - foreach($root->getChildElements(null, true) as $index => $child) { + foreach ($root->getChildElements(null, true) as $index => $child) { $this->assertSame($count++, $index); $this->assertEquals($expected[$index], $reader->name); } diff --git a/tests/unit/XMLReaderElementTest.php b/tests/unit/XMLReaderElementTest.php index 017370c..587a5b5 100644 --- a/tests/unit/XMLReaderElementTest.php +++ b/tests/unit/XMLReaderElementTest.php @@ -36,7 +36,8 @@ protected function setUp() $this->reader = new XMLReaderStub('node value'); } - public function testElementCreation() { + public function testElementCreation() + { $reader = $this->reader; $reader->next(); $element = new XMLReaderElement($reader); @@ -44,7 +45,8 @@ public function testElementCreation() { $this->assertSame($element->name, 'root'); } - public function testReaderAttributeHandling() { + public function testReaderAttributeHandling() + { $reader = new XMLReaderStub("node value"); $reader->next(); $this->assertSame("first", $reader->getAttribute('pos')); @@ -54,7 +56,8 @@ public function testReaderAttributeHandling() { $this->assertSame("", $xml, 'XML generation'); } - public function testCheckNodeValue() { + public function testCheckNodeValue() + { $reader = new XMLReaderStub('has'); /** @var XMLElementIterator|XMLReaderNode[] $it */ diff --git a/tests/unit/XMLReaderIteratorTest.php b/tests/unit/XMLReaderIteratorTest.php index 1ac2f1c..0209445 100644 --- a/tests/unit/XMLReaderIteratorTest.php +++ b/tests/unit/XMLReaderIteratorTest.php @@ -24,9 +24,10 @@ /** * Class XMLReaderIteratorTest */ -class XMLReaderIteratorTest extends PHPUnit_Framework_TestCase { - - public function testIteration() { +class XMLReaderIteratorTest extends PHPUnit_Framework_TestCase +{ + public function testIteration() + { $reader = new XMLReaderStub('12'); $it = new XMLReaderIterator($reader); From ae0cfd945d1b82ae38b58249d144036ec0feb2a6 Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 1 Sep 2025 00:00:00 +0000 Subject: [PATCH 10/12] Fixed notices in build.php. --- build.php | 26 ++++++++++++++++++++------ build.sh | 4 ++-- composer.json | 8 ++++---- {vendor => scripts}/vendor-dev.patch | 0 4 files changed, 26 insertions(+), 12 deletions(-) rename {vendor => scripts}/vendor-dev.patch (100%) diff --git a/build.php b/build.php index f92562c..ff33343 100644 --- a/build.php +++ b/build.php @@ -4,12 +4,13 @@ * This file is part of the XMLReaderIterator package. * * Copyright (C) 2012, 2013, 2014, 2015 hakre + * Copyright (C) 2025 Daniel Berthereau * * build script */ $errors = 0; -$warnings = 0; +// $warnings = 0; $projectDir = __DIR__; $buildDir = $projectDir . '/build'; @@ -35,6 +36,8 @@ function built_test_git_tag($version, &$errors) echo "INFO: Validating git tag version:"; $command = "git tag --contains HEAD"; + $output = array(); + $exitCode = null; $target = 'v' . $version; $tagName = exec($command, $output, $exitCode); @@ -92,10 +95,11 @@ function built_test_readme_get_version(&$errors) $file = 'README.md'; $data = file($file); $version = null; + $matches = array(); foreach ($data as $index => $line) { if ($line === "### Change Log:\n") { - $version = preg_match('~`(\d\.\d+\.\d+)`~', $data[$index + 2], $m) ? $m[1] : null; + $version = preg_match('~`(\d\.\d+\.\d+)`~', $data[$index + 2], $matches) ? $matches[1] : null; } if ($index > 10) { break; @@ -155,9 +159,11 @@ function built_test_composer_validate_json(&$errors) $composer = 'composer'; $command = "$composer --no-ansi --version"; + $output = array(); + $exitCode = null; exec($command, $output, $exitCode); - list($versionLine) = $output; + $versionLine = !$exitCode && $output ? reset($output) : ''; if (!preg_match('~^Composer version (?:[12]\.\d+\.\d+|1\.0-dev \([0-9a-f]{40}\)|[0-9a-f]{40}) 2\d{3}-(?:0\d|1[0-2])-(?:[0-2]\d|3[0-1]) (?:[0-1]\d|2[0-3]):[0-5]\d:(?:[0-5]\d|60)$~', $versionLine)) { echo "ERROR: Unable to invoke Composer.\n"; $errors++; @@ -189,9 +195,11 @@ function build_test_tests(&$errors) } $command = "$phpunit --version"; + $output = array(); + $exitCode = null; exec($command, $output, $exitCode); - list($versionLine) = $output + array(null); + $versionLine = !$exitCode && $output ? reset($output) : ''; if (!preg_match('~^PHPUnit \d\.\d\.\d+ by Sebastian Bergmann\.$~', $versionLine)) { echo "ERROR: Unable to invoke PHPUnit.\n"; $errors++; @@ -224,6 +232,7 @@ function build_test_tests(&$errors) function build_test_autoload_file(&$errors, $autoLoadFile) { $command = sprintf('php -f %s -- --verbose --require %s', escapeshellarg(__DIR__ . '/tests/autoload/test.php'), escapeshellarg($autoLoadFile)); + $exitCode = null; passthru($command, $exitCode); if (0 !== $exitCode) { @@ -264,6 +273,7 @@ function build_create_concatenate_file(&$errors, $concatenateFile, $autoLoadFile echo "ERROR: Problem parsing file.\n"; } $count = 0; + $matches = array(); foreach ($lines as $line) { $result = preg_match($pattern, $line, $matches); if (!$result) { @@ -378,6 +388,8 @@ function build_make_clean(&$errors, $buildDir, $concatenateDir) function build_tree_uncommitted_changes(&$errors, $workDir, $pathSpec = '.') { $command = sprintf('git -C %s status --porcelain -- %s', escapeshellarg($workDir), escapeshellarg($pathSpec)); + $output = array(); + $exitCode = null; exec($command, $output, $exitCode); if (0 !== $exitCode) { @@ -404,6 +416,8 @@ function build_tree_uncommitted_changes(&$errors, $workDir, $pathSpec = '.') function build_gist_commit(&$errors, $gistDir, $readmeVersion) { $command = sprintf('git -C %s log --format="%%B" -n 1 HEAD', escapeshellarg($gistDir)); + $output = array(); + $exitCode = null; exec($command, $output, $exitCode); if (0 !== $exitCode) { @@ -420,7 +434,7 @@ function build_gist_commit(&$errors, $gistDir, $readmeVersion) $target = "Version $readmeVersion\n\n"; $needsAmending = $gistCurrentMessage === $target; - if (true === $unchanged = !rtrim(`git diff --quiet; echo $?`)) { + if (true === !rtrim(`git diff --quiet; echo $?`)) { if (false === $needsAmending) { echo "ERROR: gist has no changes but $readmeVersion not current.\n"; $errors++; @@ -449,7 +463,7 @@ function build_gist_commit(&$errors, $gistDir, $readmeVersion) return; } - if (false === $unchanged = !rtrim(`git diff --quiet; echo $?`)) { + if (false === !rtrim(`git diff --quiet; echo $?`)) { echo "ERROR: gist still has changes after commit.\n"; $errors++; } diff --git a/build.sh b/build.sh index 69b8ea8..9b941d9 100755 --- a/build.sh +++ b/build.sh @@ -21,9 +21,9 @@ if [ ! -d vendor ]; then exit 1 fi -if [ -f vendor/vendor-dev.patch ] && command -v git &> /dev/null; then +if [ -f scripts/vendor-dev.patch ] && command -v git &> /dev/null; then git --version - git apply --unsafe-paths --directory=vendor -- vendor/vendor-dev.patch + git apply --unsafe-paths --directory=vendor -- scripts/vendor-dev.patch fi php -f build.php diff --git a/composer.json b/composer.json index 994ead5..09bd210 100644 --- a/composer.json +++ b/composer.json @@ -31,12 +31,12 @@ }, "scripts": { "post-install-cmd": [ - "# For dev, patching phpunit for compatibility with all versions of php. Require php 5.3.3 to php 7.4.", - "[ $COMPOSER_DEV_MODE -eq 0 ] || patch -d vendor -p1 < vendor/vendor-dev.patch" + "# For dev, patching phpunit for compatibility with all versions of php.", + "[ $COMPOSER_DEV_MODE -eq 0 ] || patch -d vendor -p1 < scripts/vendor-dev.patch" ], "post-update-cmd": [ - "# For dev, patching phpunit for compatibility with all versions of php. Require php 5.3.3 to php 7.4.", - "[ $COMPOSER_DEV_MODE -eq 0 ] || patch -d vendor -p1 < vendor/vendor-dev.patch" + "# For dev, patching phpunit for compatibility with all versions of php.", + "[ $COMPOSER_DEV_MODE -eq 0 ] || patch -d vendor -p1 < scripts/vendor-dev.patch" ] } } diff --git a/vendor/vendor-dev.patch b/scripts/vendor-dev.patch similarity index 100% rename from vendor/vendor-dev.patch rename to scripts/vendor-dev.patch From 238c4e1bc0f05dbe5790a8d888e2e3e7e88ad27c Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 1 Sep 2025 00:00:00 +0000 Subject: [PATCH 11/12] Updated composer for compatibility with php 8. --- composer.lock | 62 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/composer.lock b/composer.lock index f338624..a53ffbe 100644 --- a/composer.lock +++ b/composer.lock @@ -66,6 +66,11 @@ "testing", "xunit" ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/1.2.18" + }, "time": "2014-09-02T10:13:14+00:00" }, { @@ -167,30 +172,25 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "1.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": ">=5.3.3" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "~4|~5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { "classmap": [ "src/" @@ -213,10 +213,11 @@ "timer" ], "support": { + "irc": "irc://irc.freenode.net/phpunit", "issues": "https://github.com/sebastianbergmann/php-timer/issues", "source": "https://github.com/sebastianbergmann/php-timer/tree/master" }, - "time": "2017-02-26T11:10:40+00:00" + "time": "2016-05-12T18:03:57+00:00" }, { "name": "phpunit/php-token-stream", @@ -266,6 +267,11 @@ "keywords": [ "tokenizer" ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/1.2.2" + }, "abandoned": true, "time": "2014-03-03T05:10:30+00:00" }, @@ -394,25 +400,30 @@ "mock", "xunit" ], + "support": { + "irc": "irc://irc.freenode.net/phpunit", + "issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues", + "source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/1.2.3" + }, "abandoned": true, "time": "2013-01-13T10:24:48+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.25.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -422,12 +433,9 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -461,7 +469,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -472,12 +480,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/yaml", @@ -548,5 +560,5 @@ "ext-bz2": "*", "ext-libxml": "*" }, - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.3.0" } From e9e0d8c5d70237de092c61f0cd946a99ed1167cc Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 1 Sep 2025 00:00:00 +0000 Subject: [PATCH 12/12] Updated readme for version 0.1.13. --- README.md | 26 +++++++++++++++++++++++++- build/include/README.md | 26 +++++++++++++++++++++++++- build/include/xmlreader-iterators.php | 2 +- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 906d15b..e7edc60 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ ### Change Log: + - `0.1.13` fixed nested child element parsing (PR #21 on github); fixed + deprecation and notices for new php versions; normalized code and docblocks, + simplified install. + - `0.1.12` maintenance release with fixes. - `0.1.11` maintenance release with fixes. added `XMLReader::CDATA` and @@ -61,9 +65,18 @@ } ``` +### Usage + +It is recommended to use the composer autoloading mechanism. + +To use without composer and for backwards compatibility, it is possible just to +include the file `build/include/xmlreader-iterators.php` in any php project. + +Checkout the [`examples`] folder for more examples. + ### Stackoverflow Q&A for the XMLReader Iterators -the latest on top (for more examples, checkout the [`examples`] folder): +The latest Q&A on top: - [Add Tag Element using XMLReader and SimpleXML or XMLWriter](https://stackoverflow.com/q/69455574/367456) - [How to distinguish between empty element and null-size string in DOMDocument?](http://stackoverflow.com/a/24109776/367456) @@ -72,3 +85,14 @@ the latest on top (for more examples, checkout the [`examples`] folder): - [Getting XML Attribute with XMLReader and PHP](http://stackoverflow.com/a/15399491/367456) [`examples`]: https://github.com/hakre/XMLReaderIterator/tree/master/examples + +### Build + +To build the single file to use XMLReaderIterator without composer, run: + +```php +composer install +php -f build.php +``` + +The command `sh build.sh` can be used too. diff --git a/build/include/README.md b/build/include/README.md index 906d15b..e7edc60 100644 --- a/build/include/README.md +++ b/build/include/README.md @@ -4,6 +4,10 @@ ### Change Log: + - `0.1.13` fixed nested child element parsing (PR #21 on github); fixed + deprecation and notices for new php versions; normalized code and docblocks, + simplified install. + - `0.1.12` maintenance release with fixes. - `0.1.11` maintenance release with fixes. added `XMLReader::CDATA` and @@ -61,9 +65,18 @@ } ``` +### Usage + +It is recommended to use the composer autoloading mechanism. + +To use without composer and for backwards compatibility, it is possible just to +include the file `build/include/xmlreader-iterators.php` in any php project. + +Checkout the [`examples`] folder for more examples. + ### Stackoverflow Q&A for the XMLReader Iterators -the latest on top (for more examples, checkout the [`examples`] folder): +The latest Q&A on top: - [Add Tag Element using XMLReader and SimpleXML or XMLWriter](https://stackoverflow.com/q/69455574/367456) - [How to distinguish between empty element and null-size string in DOMDocument?](http://stackoverflow.com/a/24109776/367456) @@ -72,3 +85,14 @@ the latest on top (for more examples, checkout the [`examples`] folder): - [Getting XML Attribute with XMLReader and PHP](http://stackoverflow.com/a/15399491/367456) [`examples`]: https://github.com/hakre/XMLReaderIterator/tree/master/examples + +### Build + +To build the single file to use XMLReaderIterator without composer, run: + +```php +composer install +php -f build.php +``` + +The command `sh build.sh` can be used too. diff --git a/build/include/xmlreader-iterators.php b/build/include/xmlreader-iterators.php index 9f5b4d6..bb8754f 100644 --- a/build/include/xmlreader-iterators.php +++ b/build/include/xmlreader-iterators.php @@ -19,7 +19,7 @@ * * @author hakre * @license AGPL-3.0-or-later - * @version 0.1.12 + * @version 0.1.13 */ /**