From 9c0f8a5d4b581bf93d32a4921c3ed1ef9ffbe90c Mon Sep 17 00:00:00 2001 From: Norbert Orzechowicz <1921950+norberttech@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:28:07 +0200 Subject: [PATCH] Restored original behavior of DOMElementValue function combined with XPath (#1220) --- examples/topics/data_source/xml/output.txt | 28 +++---- .../ETL/Function/DOMElementAttributeValue.php | 15 +++- .../src/Flow/ETL/Function/DOMElementValue.php | 14 +++- .../etl/src/Flow/ETL/Function/Parameter.php | 17 ++++ .../Function/DOMElementAttributeValueTest.php | 77 +++++++++++++++++++ .../Function/DOMElementValueTest.php | 77 +++++++++++++++++++ 6 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 src/core/etl/tests/Flow/ETL/Tests/Integration/Function/DOMElementAttributeValueTest.php create mode 100644 src/core/etl/tests/Flow/ETL/Tests/Integration/Function/DOMElementValueTest.php diff --git a/examples/topics/data_source/xml/output.txt b/examples/topics/data_source/xml/output.txt index 579a68f92..b7dbc290e 100644 --- a/examples/topics/data_source/xml/output.txt +++ b/examples/topics/data_source/xml/output.txt @@ -1,15 +1,15 @@ -+----+------+--------+-------+ -| id | name | active | email | -+----+------+--------+-------+ -| 1 | | | | -| 2 | | | | -| 3 | | | | -| 4 | | | | -| 5 | | | | -| 6 | | | | -| 7 | | | | -| 8 | | | | -| 9 | | | | -| 10 | | | | -+----+------+--------+-------+ ++----+---------+--------+---------------------+ +| id | name | active | email | ++----+---------+--------+---------------------+ +| 1 | Alice | true | alice@example.com | +| 2 | Bob | false | bob@example.com | +| 3 | Charlie | true | charlie@example.com | +| 4 | David | false | david@example.com | +| 5 | Emma | true | emma@example.com | +| 6 | Frank | false | frank@example.com | +| 7 | Grace | true | grace@example.com | +| 8 | Harry | false | harry@example.com | +| 9 | Isla | true | isla@example.com | +| 10 | James | false | james@example.com | ++----+---------+--------+---------------------+ 10 rows diff --git a/src/core/etl/src/Flow/ETL/Function/DOMElementAttributeValue.php b/src/core/etl/src/Flow/ETL/Function/DOMElementAttributeValue.php index 2784cd3cb..ca5820e73 100644 --- a/src/core/etl/src/Flow/ETL/Function/DOMElementAttributeValue.php +++ b/src/core/etl/src/Flow/ETL/Function/DOMElementAttributeValue.php @@ -16,7 +16,20 @@ public function __construct( public function eval(Row $row) : ?string { - $domElement = (new Parameter($this->domElement))->asInstanceOf($row, \DOMElement::class); + $domElement = Parameter::oneOf( + (new Parameter($this->domElement))->asInstanceOf($row, \DOMElement::class), + (new Parameter($this->domElement))->asInstanceOf($row, \DOMDocument::class), + (new Parameter($this->domElement))->asListOfObjects($row, \DOMElement::class), + ); + + if ($domElement instanceof \DOMDocument) { + $domElement = $domElement->documentElement; + } + + if (\is_array($domElement) && \count($domElement)) { + $domElement = \reset($domElement); + } + $attributeName = (new Parameter($this->attribute))->asString($row); if ($domElement === null || $attributeName === null) { diff --git a/src/core/etl/src/Flow/ETL/Function/DOMElementValue.php b/src/core/etl/src/Flow/ETL/Function/DOMElementValue.php index d214869db..957a117c4 100644 --- a/src/core/etl/src/Flow/ETL/Function/DOMElementValue.php +++ b/src/core/etl/src/Flow/ETL/Function/DOMElementValue.php @@ -14,7 +14,19 @@ public function __construct(private readonly ScalarFunction|\DOMElement $domElem public function eval(Row $row) : mixed { - $domElement = (new Parameter($this->domElement))->asInstanceOf($row, \DOMElement::class); + $domElement = Parameter::oneOf( + (new Parameter($this->domElement))->asInstanceOf($row, \DOMElement::class), + (new Parameter($this->domElement))->asInstanceOf($row, \DOMDocument::class), + (new Parameter($this->domElement))->asListOfObjects($row, \DOMElement::class), + ); + + if (\is_array($domElement) && \count($domElement)) { + $domElement = \reset($domElement); + } + + if ($domElement instanceof \DOMDocument) { + $domElement = $domElement->documentElement; + } if (!$domElement instanceof \DOMElement) { return null; diff --git a/src/core/etl/src/Flow/ETL/Function/Parameter.php b/src/core/etl/src/Flow/ETL/Function/Parameter.php index 282bd274f..a46d03158 100644 --- a/src/core/etl/src/Flow/ETL/Function/Parameter.php +++ b/src/core/etl/src/Flow/ETL/Function/Parameter.php @@ -97,6 +97,23 @@ public function asInt(Row $row) : ?int return \is_int($result) ? $result : null; } + public function asListOfObjects(Row $row, string $class) : ?array + { + $result = $this->function->eval($row); + + if (!\is_array($result)) { + return null; + } + + foreach ($result as $item) { + if (!\is_object($item) || !\is_a($item, $class)) { + return null; + } + } + + return $result; + } + /** * @psalm-suppress InvalidReturnType * @psalm-suppress InvalidReturnStatement diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/DOMElementAttributeValueTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/DOMElementAttributeValueTest.php new file mode 100644 index 000000000..17ca36de1 --- /dev/null +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/DOMElementAttributeValueTest.php @@ -0,0 +1,77 @@ +read(from_rows( + rows( + row( + xml_element_entry('node', 'User Name 01') + ) + ) + )) + ->withEntry('user_id', ref('node')->domElementAttributeValue('id')) + ->drop('node') + ->fetch(); + + self::assertSame( + [ + ['user_id' => '1'], + ], + $rows->toArray() + ); + } + + public function test_dom_element_attribute_value_from_dom_document() : void + { + $rows = df() + ->read(from_rows( + rows( + row( + xml_entry('node', 'User Name 01') + ) + ) + )) + ->withEntry('user_id', ref('node')->domElementAttributeValue('id')) + ->drop('node') + ->fetch(); + + self::assertSame( + [ + ['user_id' => '1'], + ], + $rows->toArray() + ); + } + + public function test_dom_element_attribute_value_on_xpath_result() : void + { + $rows = df() + ->read(from_rows( + rows( + row( + xml_entry('node', 'User Name 01') + ) + ) + )) + ->withEntry('user_id', ref('node')->xpath('name')->domElementAttributeValue('id')) + ->drop('node') + ->fetch(); + + self::assertSame( + [ + ['user_id' => '1'], + ], + $rows->toArray() + ); + } +} diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/DOMElementValueTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/DOMElementValueTest.php new file mode 100644 index 000000000..4498f325f --- /dev/null +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/DOMElementValueTest.php @@ -0,0 +1,77 @@ +read(from_rows( + rows( + row( + xml_element_entry('node', 'User Name 01') + ) + ) + )) + ->withEntry('user_name', ref('node')->domElementValue()) + ->drop('node') + ->fetch(); + + self::assertSame( + [ + ['user_name' => 'User Name 01'], + ], + $rows->toArray() + ); + } + + public function test_dom_element_value_from_dom_document() : void + { + $rows = df() + ->read(from_rows( + rows( + row( + xml_entry('node', 'User Name 01') + ) + ) + )) + ->withEntry('user_name', ref('node')->domElementValue()) + ->drop('node') + ->fetch(); + + self::assertSame( + [ + ['user_name' => 'User Name 01'], + ], + $rows->toArray() + ); + } + + public function test_dom_element_value_on_xpath_result() : void + { + $rows = df() + ->read(from_rows( + rows( + row( + xml_entry('node', 'User Name 01') + ) + ) + )) + ->withEntry('user_name', ref('node')->xpath('name')->domElementValue()) + ->drop('node') + ->fetch(); + + self::assertSame( + [ + ['user_name' => 'User Name 01'], + ], + $rows->toArray() + ); + } +}