diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml
index a781440..fc5f29a 100644
--- a/.github/workflows/phpunit.yml
+++ b/.github/workflows/phpunit.yml
@@ -12,18 +12,50 @@ on:
jobs:
Build:
runs-on: 'ubuntu-latest'
- container: 'byjg/php:${{ matrix.php-version }}-cli'
+ container:
+ image: 'byjg/php:${{ matrix.php-version }}-cli'
+ options: --user root --privileged
strategy:
matrix:
php-version:
+ - "8.5"
+ - "8.4"
- "8.3"
- - "8.2"
- - "8.1"
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- run: composer install
- - run: ./vendor/bin/phpunit
+ - run: composer test
+
+ Psalm:
+ name: Psalm Static Analyzer
+ runs-on: ubuntu-latest
+ permissions:
+ # for github/codeql-action/upload-sarif to upload SARIF results
+ security-events: write
+ container:
+ image: byjg/php:8.4-cli
+ options: --user root --privileged
+
+ steps:
+ - name: Git checkout
+ uses: actions/checkout@v4
+
+ - name: Composer
+ run: composer install
+
+ - name: Psalm
+ # Note: Ignoring error code 2, which just signals that some
+ # flaws were found, not that Psalm itself failed to run.
+ run: ./vendor/bin/psalm
+ --show-info=true
+ --report=psalm-results.sarif || [ $? = 2 ]
+
+ - name: Upload Analysis results to GitHub
+ uses: github/codeql-action/upload-sarif@v4
+ if: github.ref == 'refs/heads/master'
+ with:
+ sarif_file: psalm-results.sarif
Documentation:
if: github.ref == 'refs/heads/master'
@@ -32,5 +64,6 @@ jobs:
with:
folder: php
project: ${{ github.event.repository.name }}
- secrets: inherit
+ secrets:
+ DOC_TOKEN: ${{ secrets.DOC_TOKEN }}
diff --git a/.run/PHPUnit.run.xml b/.run/PHPUnit.run.xml
new file mode 100644
index 0000000..f81c245
--- /dev/null
+++ b/.run/PHPUnit.run.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/psalm.run.xml b/.run/psalm.run.xml
new file mode 100644
index 0000000..d9c1b61
--- /dev/null
+++ b/.run/psalm.run.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..a8c1b2a
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,35 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Debug current Script in Console",
+ "type": "php",
+ "request": "launch",
+ "program": "${file}",
+ "cwd": "${fileDirname}",
+ "port": 9003,
+ "runtimeArgs": [
+ "-dxdebug.start_with_request=yes"
+ ],
+ "env": {
+ "XDEBUG_MODE": "debug,develop",
+ "XDEBUG_CONFIG": "client_port=${port}"
+ }
+ },
+ {
+ "name": "PHPUnit Debug",
+ "type": "php",
+ "request": "launch",
+ "program": "${workspaceFolder}/vendor/bin/phpunit",
+ "cwd": "${workspaceFolder}",
+ "port": 9003,
+ "runtimeArgs": [
+ "-dxdebug.start_with_request=yes"
+ ],
+ "env": {
+ "XDEBUG_MODE": "debug,develop",
+ "XDEBUG_CONFIG": "client_port=${port}"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 652d019..654a123 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,44 @@
# AnyDataset-Xml
-[](https://github.com/byjg/php-anydataset-xml/actions/workflows/phpunit.yml)
-[](http://opensource.byjg.com)
-[](https://github.com/byjg/php-anydataset-xml/)
-[](https://opensource.byjg.com/opensource/licensing.html)
+[](https://github.com/sponsors/byjg)
+[](https://github.com/byjg/php-anydataset-xml/actions/workflows/phpunit.yml)
+[](http://opensource.byjg.com)
+[](https://github.com/byjg/php-anydataset-xml/)
+[](https://opensource.byjg.com/opensource/licensing.html)
[](https://github.com/byjg/php-anydataset-xml/releases/)
-XML abstraction dataset. Anydataset is an agnostic data source abstraction layer in PHP.
-
-See more about Anydataset [here](https://opensource.byjg.com/php/anydataset).
-
-## Examples
-
-### Simple Manipulation
-
-example1.xml
-```xml
-
-
-
- Everyday Italian
- Giada De Laurentiis
- 2005
- 30.00
-
-
- Harry Potter
- J K. Rowling
- 2005
- 29.99
-
-
- Learning XML
- Erik T. Ray
- 2003
- 39.95
-
-
+XML abstraction dataset for the AnyDataset library. AnyDataset is an agnostic data source abstraction layer in PHP.
+
+## Features
+
+- **Simple XML Processing**: Process XML data with a clean, consistent API
+- **XPath Support**: Use XPath expressions to select nodes and attributes
+- **Namespace Support**: Full support for XML namespaces
+- **Repeated Node Handling**: Automatically handles repeated nodes by returning arrays
+- **Custom Field Processing**: Define custom field mappings with closures/callbacks
+- **Flexible Input**: Accept XML as string, DOMDocument, XmlNode, or File object
+- **AnyDataset Integration**: Compatible with the AnyDataset abstraction layer
+
+## Documentation
+
+- [XmlDataset](docs/XmlDataset.md) - Main class for working with XML data
+- [XPath Expressions](docs/XPath-Expressions.md) - Guide to using XPath in the library
+
+## Installation
+
+```bash
+composer require "byjg/anydataset-xml"
```
-example1.php
+## Quick Example
+
```php
"@category",
"title" => "title",
@@ -60,99 +52,25 @@ $dataset = new \ByJG\AnyDataset\Xml\XmlDataset(
$iterator = $dataset->getIterator();
foreach ($iterator as $row) {
echo $row->get('category'); // Print COOKING, CHILDREN, WEB
- echo $row->get('title'); // Print Everyday Italian, Harry Potter, Learning Xml
+ echo $row->get('title'); // Print Everyday Italian, Harry Potter, Learning XML
echo $row->get('lang'); // Print en-US, de-DE, pt-BR
echo $row->get('lang2'); // Print en, de, pt
}
```
-### Xml with namespaces
-
-example2.xml
-```xml
-
-
- myId
- 2014-09-15T19:35:55.795Z
-
- Title
-
-
-
-
-
-
-
- My Name
- My Email
-
- Contacts
- 2107
- 1
- 20
-
- http://www.google.com/m8/feeds/contacts/my%40gmail.com/base/0
- 2013-10-05T22:16:03.564Z
-
- Person 1
-
-
-
-
-
-
-
- http://www.google.com/m8/feeds/contacts/my%40gmail.com/base/1
- 2012-07-12T17:19:17.546Z
-
- Person 2
-
-
-
-
-
-
-```
-
-example2.php
-```php
- "http://www.w3.org/2005/Atom",
- "gd" => "http://schemas.google.com/g/2005"
-);
-
-$rootNode = 'fake:entry';
-$colNode = array("id" => "fake:id", "updated" => "fake:updated", "name" => "fake:title", "email" => "gd:email/@address");
-$xmlDataset = new \ByJG\AnyDataset\Xml\XmlDataset(
- $xml,
- $rootNode,
- $colNode,
- $namespace
-);
-$xmlIterator = $xmlDataset->getIterator();
-```
-
-## Install
+## Dependencies
-```
-composer require "byjg/anydataset-xml"
+```mermaid
+flowchart TD
+ byjg/anydataset-xml --> byjg/anydataset
+ byjg/anydataset-xml --> ext-dom
```
-## Running the Unit tests
+## Running the Unit Tests
```bash
vendor/bin/phpunit
```
-## Dependencies
-
-```mermaid
-flowchart TD
- byjg/anydataset-xml --> byjg/anydataset
- byjg/anydataset-xml --> ext-dom
-```
----
[Open source ByJG](http://opensource.byjg.com)
diff --git a/composer.json b/composer.json
index c2e41ab..734c410 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,6 @@
{
"name": "byjg/anydataset-xml",
- "description": "Anydataset Xml abstraction. Anydataset is an agnostic data source abstraction layer in PHP.",
+ "description": "XML abstraction dataset for the AnyDataset library. AnyDataset is an agnostic data source abstraction layer in PHP.",
"autoload": {
"psr-4": {
"ByJG\\AnyDataset\\Xml\\": "src/"
@@ -14,15 +14,20 @@
"prefer-stable": true,
"minimum-stability": "dev",
"require": {
- "php": ">=8.1 <8.4",
+ "php": ">=8.3 <8.6",
"ext-dom": "*",
- "byjg/anydataset": "^5.0"
+ "byjg/anydataset": "^6.0"
},
"require-dev": {
- "phpunit/phpunit": "^9.6"
+ "phpunit/phpunit": "^10.5|^11.5",
+ "vimeo/psalm": "^5.9|^6.13"
},
"provide": {
"byjg/anydataset-implementation": "1.0"
},
+ "scripts": {
+ "test": "vendor/bin/phpunit",
+ "psalm": "vendor/bin/psalm"
+ },
"license": "MIT"
}
diff --git a/docs/XPath-Expressions.md b/docs/XPath-Expressions.md
new file mode 100644
index 0000000..14bd02d
--- /dev/null
+++ b/docs/XPath-Expressions.md
@@ -0,0 +1,128 @@
+---
+sidebar_position: 2
+title: XPath Expressions
+---
+
+# XPath Expressions in AnyDataset-Xml
+
+This library uses XPath expressions to select nodes and attributes from XML documents. Understanding XPath is essential for effectively using the AnyDataset-Xml library.
+
+## Basic XPath Syntax
+
+Here are some common XPath expressions used in the library:
+
+| Expression | Description | Example |
+|----------------------|------------------------------------------------------------------|----------------------------------------------------------------------------------------|
+| `element` | Selects all elements with the given name | `"title"` selects all `
` elements |
+| `@attribute` | Selects the attribute with the given name | `"@category"` selects the category attribute |
+| `element/@attribute` | Selects an attribute of an element | `"title/@lang"` selects the lang attribute of title elements |
+| `parent/child` | Selects all child elements of the parent | `"book/author"` selects all author elements that are children of book elements |
+| `//element` | Selects all elements with the given name, regardless of position | `"//title"` selects all title elements anywhere in the document |
+| `*` | Selects all elements | `"book/*"` selects all child elements of book |
+| `element[n]` | Selects the nth element | `"author[1]"` selects the first author element |
+| `element[condition]` | Selects elements that satisfy the condition | `"book[@category='WEB']"` selects book elements with category attribute equal to 'WEB' |
+
+## Implementation Details
+
+:::warning Key Points
+- All field names in the resulting data are converted to lowercase
+- If an XPath expression doesn't match any nodes, an empty string is returned for that field
+- If an XPath expression matches multiple nodes, all values are collected automatically in an array
+:::
+
+## Examples in AnyDataset-Xml
+
+### Basic Element Selection
+
+```php
+$colNodes = [
+ "title" => "title", // Selects the element
+ "author" => "author", // Selects the element
+ "year" => "year", // Selects the element
+ "price" => "price" // Selects the element
+];
+```
+
+### Attribute Selection
+
+```php
+$colNodes = [
+ "category" => "@category", // Selects the category attribute of the current node
+ "lang" => "title/@lang" // Selects the lang attribute of the title element
+];
+```
+
+### Using Namespaces
+
+When working with namespaced XML, you need to register the namespaces and use them in your XPath expressions:
+
+```php
+$namespace = [
+ "atom" => "http://www.w3.org/2005/Atom",
+ "gd" => "http://schemas.google.com/g/2005"
+];
+
+$colNodes = [
+ "id" => "atom:id", // Selects the id element in the atom namespace
+ "email" => "gd:email/@address" // Selects the address attribute of the email element in the gd namespace
+];
+
+$dataset = new \ByJG\AnyDataset\Xml\XmlDataset(
+ $xml,
+ "atom:entry", // Selects entry elements in the atom namespace
+ $colNodes,
+ $namespace
+);
+```
+
+## Advanced Usage
+
+### Custom Field Processing
+
+You can use callback functions to process field values:
+
+```php
+$colNodes = [
+ "title" => "title",
+ "lang" => "title/@lang",
+ "shortLang" => function ($row) {
+ return substr($row->get('lang'), 0, 2);
+ }
+];
+```
+
+### Handling Repeated Nodes
+
+When an XPath expression matches multiple nodes, the values are automatically collected in an array:
+
+```php
+// For XML like:
+//
+// Author 1
+// Author 2
+//
+
+$colNodes = [
+ "authors" => "author" // Will automatically return an array of all author values: ["Author 1", "Author 2"]
+];
+
+// Access as:
+$authorArray = $row->get('authors');
+```
+
+### Accessing Field Values
+
+:::caution Case Sensitivity
+All field names are converted to lowercase when accessed through the iterator.
+:::
+
+```php
+$colNodes = [
+ "Title" => "title",
+ "AUTHOR" => "author"
+];
+
+// Access using lowercase:
+$title = $row->get('title'); // Not $row->get('Title')
+$author = $row->get('author'); // Not $row->get('AUTHOR')
+```
\ No newline at end of file
diff --git a/docs/XmlDataset.md b/docs/XmlDataset.md
new file mode 100644
index 0000000..bb80ac5
--- /dev/null
+++ b/docs/XmlDataset.md
@@ -0,0 +1,135 @@
+---
+sidebar_position: 1
+title: XmlDataset
+---
+
+# XmlDataset
+
+The `XmlDataset` class is the main entry point for working with XML data in the AnyDataset library.
+
+## Basic Usage
+
+```php
+$dataset = new \ByJG\AnyDataset\Xml\XmlDataset(
+ $xml, // The XML string, can also be an XmlNode, DOMDocument, or File object
+ "book", // The node that represents a row
+ [
+ "category" => "@category",
+ "title" => "title",
+ "lang" => "title/@lang",
+ ] // Mapping columns
+);
+
+$iterator = $dataset->getIterator();
+foreach ($iterator as $row) {
+ echo $row->get('category');
+ echo $row->get('title');
+ echo $row->get('lang');
+}
+```
+
+## Constructor Parameters
+
+```php
+public function __construct(
+ XmlNode|DOMDocument|string|File $xml,
+ string $rowNode,
+ array $colNode,
+ array $registerNS = []
+)
+```
+
+- **$xml**: The XML source. Can be:
+ - A string containing XML
+ - An XmlNode object
+ - A DOMDocument object
+ - A File object
+
+- **$rowNode**: XPath expression that identifies the nodes to be treated as rows
+
+- **$colNode**: Associative array mapping field names to XPath expressions
+ - Keys: The field names that will be accessible in the iterator (will be converted to lowercase)
+ - Values: XPath expressions relative to the row node, or callback functions
+
+- **$registerNS**: Optional array of namespace prefixes and URIs
+
+## Methods
+
+### getIterator()
+
+```php
+public function getIterator(): GenericIterator
+```
+
+Returns an `XmlIterator` instance that can be used to iterate through the XML data.
+
+## Field Values Handling
+
+:::info Important Behavior
+- When an XPath expression matches multiple nodes, the values are automatically collected in an array
+- All field names are converted to lowercase when accessed through the iterator
+- If no nodes match an XPath expression, an empty string is returned for that field
+:::
+
+## Examples
+
+### Basic Example
+
+```php
+$xml = file_get_contents('example.xml');
+
+$dataset = new \ByJG\AnyDataset\Xml\XmlDataset(
+ $xml,
+ "book",
+ [
+ "category" => "@category",
+ "title" => "title",
+ "lang" => "title/@lang"
+ ]
+);
+
+$iterator = $dataset->getIterator();
+foreach ($iterator as $row) {
+ echo $row->get('category'); // Print attribute values
+ echo $row->get('title'); // Print element values
+ echo $row->get('lang'); // Print attribute of an element
+}
+```
+
+### With Custom Field Processing
+
+```php
+$dataset = new \ByJG\AnyDataset\Xml\XmlDataset(
+ $xml,
+ "book",
+ [
+ "category" => "@category",
+ "title" => "title",
+ "lang" => "title/@lang",
+ "lang2" => function ($row) {
+ return substr($row->get('lang'), 0, 2);
+ }
+ ]
+);
+```
+
+### With Namespaces
+
+```php
+$namespace = [
+ "atom" => "http://www.w3.org/2005/Atom",
+ "gd" => "http://schemas.google.com/g/2005"
+];
+
+$dataset = new \ByJG\AnyDataset\Xml\XmlDataset(
+ $xml,
+ "atom:entry",
+ [
+ "id" => "atom:id",
+ "updated" => "atom:updated",
+ "name" => "atom:title",
+ "email" => "gd:email/@address"
+ ],
+ $namespace
+);
+```
\ No newline at end of file
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index f01d221..711a9b0 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -4,33 +4,33 @@ To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
-
-
+ displayDetailsOnTestsThatTriggerDeprecations="true"
+ displayDetailsOnTestsThatTriggerErrors="true"
+ displayDetailsOnTestsThatTriggerNotices="true"
+ displayDetailsOnTestsThatTriggerWarnings="true"
+ displayDetailsOnPhpunitDeprecations="true"
+ stopOnFailure="false"
+ xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd">
+
+
+
+
+
-
-
-
-
-
+
+
+ ./src/
+
+
-
-
- ./src
-
-
-
-
-
- ./tests
-
-
-
+
+
+ ./tests/
+
+
diff --git a/psalm.xml b/psalm.xml
new file mode 100644
index 0000000..037de8b
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/XmlDataset.php b/src/XmlDataset.php
index c80d6df..858d465 100644
--- a/src/XmlDataset.php
+++ b/src/XmlDataset.php
@@ -3,13 +3,12 @@
namespace ByJG\AnyDataset\Xml;
use ByJG\AnyDataset\Core\GenericIterator;
-use ByJG\AnyDataset\Core\Exception\DatasetException;
+use ByJG\XmlUtil\Exception\FileException;
use ByJG\XmlUtil\Exception\XmlUtilException;
use ByJG\XmlUtil\File;
use ByJG\XmlUtil\XmlDocument;
use ByJG\XmlUtil\XmlNode;
use DOMDocument;
-use InvalidArgumentException;
class XmlDataset
{
@@ -26,7 +25,7 @@ class XmlDataset
*
* @var string[]
*/
- private ?array $colNodes;
+ private array $colNodes;
/**
* @var XmlDocument
@@ -42,9 +41,10 @@ class XmlDataset
/**
* @param XmlNode|DOMDocument|string|File $xml
* @param string $rowNode
- * @param string[] $colNode
+ * @param array $colNode
* @param array $registerNS
* @throws XmlUtilException
+ * @throws FileException
*/
public function __construct(XmlNode|DOMDocument|string|File $xml, string $rowNode, array $colNode, array $registerNS = [])
{
diff --git a/src/XmlIterator.php b/src/XmlIterator.php
index 6cd697b..4b5f24e 100644
--- a/src/XmlIterator.php
+++ b/src/XmlIterator.php
@@ -3,12 +3,14 @@
namespace ByJG\AnyDataset\Xml;
use ByJG\AnyDataset\Core\GenericIterator;
-use ByJG\AnyDataset\Core\Exception\IteratorException;
use ByJG\AnyDataset\Core\Row;
+use ByJG\AnyDataset\Core\RowArray;
+use ByJG\AnyDataset\Core\RowInterface;
use ByJG\XmlUtil\Exception\XmlUtilException;
use ByJG\XmlUtil\XmlNode;
use DOMNodeList;
-use InvalidArgumentException;
+use Override;
+use ReturnTypeWillChange;
class XmlIterator extends GenericIterator
{
@@ -16,94 +18,108 @@ class XmlIterator extends GenericIterator
/**
* Enter description here...
*
- * @var DOMNodeList|null
+ * @var DOMNodeList
*/
- private ?DOMNodeList $nodeList = null;
+ private DOMNodeList $nodeList;
/**
* Enter description here...
*
* @var string[]
*/
- private ?array $colNodes = null;
+ private array $colNodes;
+
+ private ?RowInterface $currentRow = null;
+ private int $currentIndex = 0;
- /**
- * Enter description here...
- *
- * @var int
- */
- private int $current = 0;
protected array $registerNS;
- public function __construct(DOMNodeList $nodeList, array $colNodes, array $registerNS = null)
+ public function __construct(DOMNodeList $nodeList, array $colNodes, ?array $registerNS = null)
{
- $this->registerNS = $registerNS;
+ $this->registerNS = $registerNS ?? [];
$this->nodeList = $nodeList;
$this->colNodes = $colNodes;
-
- $this->current = 0;
- }
-
- public function count(): int
- {
- return $this->nodeList->length;
}
/**
- * @access public
- * @return bool
+ * @throws XmlUtilException
*/
- public function hasNext(): bool
+ protected function parseXmlNode(): ?RowInterface
{
- if ($this->current < $this->count()) {
- return true;
+ if (!$this->valid()) {
+ return null;
}
- return false;
- }
+ $rowNumber = $this->currentIndex;
+ $node = $this->nodeList->item($rowNumber);
- /**
- * @access public
- * @return Row|null
- * @throws IteratorException
- * @throws XmlUtilException
- */
- public function moveNext(): ?Row
- {
- if (!$this->hasNext()) {
+ if ($node === null) {
return null;
}
- $node = $this->nodeList->item($this->current++);
-
- $row = new Row();
+ $row = new RowArray();
$callables = [];
- foreach ($this->colNodes as $key => $colxpath) {
- if (is_callable($colxpath)) {
- $callables[$key] = $colxpath;
+ $xmlNode = XmlNode::instance($node);
+ $lowercaseKeys = array_map('strtolower', array_keys($this->colNodes));
+ $this->colNodes = array_combine($lowercaseKeys, array_values($this->colNodes));
+ foreach ($this->colNodes as $key => $colXpath) {
+ if (is_callable($colXpath)) {
+ $callables[$key] = $colXpath;
continue;
}
- $nodeCol = XmlNode::instance($node)->selectNodes($colxpath, $this->registerNS);
+ $nodeCol = $xmlNode->selectNodes($colXpath, $this->registerNS);
if ($nodeCol->count() == 0) {
- $row->addField(strtolower($key), "");
+ $row->set($key, "");
} else {
foreach ($nodeCol as $col) {
- $row->addField(strtolower($key), $col->nodeValue);
+ $row->set($key, $col->nodeValue, append: true);
}
}
}
foreach ($callables as $key => $callable) {
- $row->addField(strtolower($key), $callable($row));
+ $row->set($key, $callable($row), append: true);
}
+ $this->currentRow = $row;
+
return $row;
}
+ #[ReturnTypeWillChange]
+ #[Override]
public function key(): int
{
- return $this->current;
+ return $this->currentIndex;
+ }
+
+ /**
+ * @return RowInterface|null
+ */
+ #[ReturnTypeWillChange]
+ #[Override]
+ public function current(): ?RowInterface
+ {
+ if ($this->currentRow === null) {
+ $this->parseXmlNode();
+ }
+ return $this->currentRow;
+ }
+
+ #[ReturnTypeWillChange]
+ #[Override]
+ public function next(): void
+ {
+ $this->currentIndex++;
+ $this->currentRow = null;
+ }
+
+ #[ReturnTypeWillChange]
+ #[Override]
+ public function valid(): bool
+ {
+ return ($this->currentIndex < count($this->nodeList));
}
}
diff --git a/tests/XmlDatasetTest.php b/tests/XmlDatasetTest.php
index 96e4318..d33e0dd 100644
--- a/tests/XmlDatasetTest.php
+++ b/tests/XmlDatasetTest.php
@@ -4,8 +4,10 @@
use ByJG\AnyDataset\Core\IteratorInterface;
use ByJG\AnyDataset\Core\Row;
+use ByJG\AnyDataset\Core\RowInterface;
use ByJG\AnyDataset\Xml\XmlDataset;
use ByJG\XmlUtil\Exception\XmlUtilException;
+use Override;
use PHPUnit\Framework\TestCase;
class XmlDatasetTest extends TestCase
@@ -40,6 +42,7 @@ class XmlDatasetTest extends TestCase
protected $arrTest2 = array();
// Run before each test case
+ #[Override]
public function setUp(): void
{
$this->arrTest = array();
@@ -58,9 +61,8 @@ public function testcreateXMLDataset()
$xmlDataset = new XmlDataset(XmlDatasetTest::XML_OK, $this->rootNode, $this->arrColumn);
$xmlIterator = $xmlDataset->getIterator();
- $this->assertTrue($xmlIterator instanceof IteratorInterface);
- $this->assertTrue($xmlIterator->hasNext());
- $this->assertEquals($xmlIterator->Count(), 3);
+ $this->assertTrue($xmlIterator->valid());
+ $this->assertCount(3, $xmlIterator->toArray());
}
public function testnavigateXMLIterator()
@@ -69,8 +71,9 @@ public function testnavigateXMLIterator()
$xmlIterator = $xmlDataset->getIterator();
$count = 0;
- while ($xmlIterator->hasNext()) {
- $this->assertSingleRow($xmlIterator->moveNext(), $count++);
+ while ($xmlIterator->valid()) {
+ $this->assertSingleRow($xmlIterator->current(), $count++);
+ $xmlIterator->next();
}
$this->assertEquals($count, 3);
@@ -100,7 +103,7 @@ public function testwrongNodeRoot()
$xmlDataset = new XmlDataset(XmlDatasetTest::XML_OK, "wrong", $this->arrColumn);
$xmlIterator = $xmlDataset->getIterator();
- $this->assertEquals($xmlIterator->count(), 0);
+ $this->assertCount(0, $xmlIterator->toArray());
}
public function testwrongColumn()
@@ -108,7 +111,7 @@ public function testwrongColumn()
$xmlDataset = new XmlDataset(XmlDatasetTest::XML_OK, $this->rootNode, array("title" => "aaaa"));
$xmlIterator = $xmlDataset->getIterator();
- $this->assertEquals($xmlIterator->count(), 3);
+ $this->assertCount(3, $xmlIterator->toArray());
}
public function testrepeatedNodes()
@@ -123,22 +126,20 @@ public function testrepeatedNodes()
30.00
';
- $xmlDataset = new XmlDataset($xml, $this->rootNode, array("author" => "author"));
+ $xmlDataset = new XmlDataset($xml, $this->rootNode, array("AUTHOR" => "author")); // It will be converted to author
$xmlIterator = $xmlDataset->getIterator();
- $this->assertTrue($xmlIterator instanceof IteratorInterface);
- $this->assertTrue($xmlIterator->hasNext());
- $this->assertEquals(1, $xmlIterator->Count());
+ $this->assertTrue($xmlIterator->valid());
- $sr = $xmlIterator->moveNext();
- $authors = $sr->getAsArray('author');
+ $sr = $xmlIterator->current();
+ $authors = $sr->get('author');
$this->assertEquals(2, count($authors));
$this->assertEquals('Giada De Laurentiis', $authors[0]);
$this->assertEquals('Another Author', $authors[1]);
}
- public function testatomXml()
+ public function testAtomXml()
{
$xml = '
myId
@@ -152,7 +153,7 @@ public function testatomXml()
- My Name
+ My Name
My Email
Contacts
@@ -187,22 +188,30 @@ public function testatomXml()
"gd" => "http://schemas.google.com/g/2005"
);
$rootNode = 'fake:entry';
- $colNode = array("id" => "fake:id", "updated" => "fake:updated", "name" => "fake:title", "email" => "gd:email/@address", "item" => function($row) { return $row->get("name") . " - " . $row->get("email"); });
+ $colNode = [
+ "id" => "fake:id",
+ "updated" => "fake:updated",
+ "name" => "fake:title",
+ "email" => "gd:email/@address",
+ "item" => function($row) { return $row->get("name") . " - " . $row->get("email"); }
+ ];
$xmlDataset = new XmlDataset($xml, $rootNode, $colNode, $namespace);
$xmlIterator = $xmlDataset->getIterator();
- $this->assertTrue($xmlIterator instanceof IteratorInterface);
- $this->assertTrue($xmlIterator->hasNext());
- $this->assertEquals(2, $xmlIterator->Count());
+ $this->assertTrue($xmlIterator->valid());
- $row = $xmlIterator->moveNext();
+ $rowCur = $xmlIterator->current();
+
+ $row = $rowCur;
$this->assertEquals("http://www.google.com/m8/feeds/contacts/my%40gmail.com/base/0", $row->get("id"));
$this->assertEquals("2013-10-05T22:16:03.564Z", $row->get("updated"));
$this->assertEquals("Person 1", $row->get("name"));
$this->assertEquals("p1@gmail.com", $row->get("email"));
$this->assertEquals("Person 1 - p1@gmail.com", $row->get("item"));
+ $this->assertEquals($row, $rowCur);
- $row = $xmlIterator->moveNext();
+ $xmlIterator->next();
+ $row = $xmlIterator->current();
$this->assertEquals("http://www.google.com/m8/feeds/contacts/my%40gmail.com/base/1", $row->get("id"));
$this->assertEquals("2012-07-12T17:19:17.546Z", $row->get("updated"));
$this->assertEquals("Person 2", $row->get("name"));
@@ -212,13 +221,13 @@ public function testatomXml()
/**
- * @param Row $sr
+ * @param RowInterface $sr
*/
public function assertSingleRow($sr, $count)
{
- $this->assertEquals($sr->get("category"), $this->arrTest[$count]["category"]);
- $this->assertEquals($sr->get("title"), $this->arrTest[$count]["title"]);
- $this->assertEquals($sr->get("lang"), $this->arrTest[$count]["lang"]);
+ $this->assertEquals($this->arrTest[$count]["category"], $sr->get("category"), "Row $count");
+ $this->assertEquals($this->arrTest[$count]["title"], $sr->get("title"), "Row $count");
+ $this->assertEquals($this->arrTest[$count]["lang"], $sr->get("lang"), "Row $count");
}
}