Skip to content

Commit

Permalink
Restored original behavior of DOMElementValue function combined with …
Browse files Browse the repository at this point in the history
…XPath (#1220)
  • Loading branch information
norberttech committed Sep 12, 2024
1 parent e56255c commit 9c0f8a5
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 16 deletions.
28 changes: 14 additions & 14 deletions examples/topics/data_source/xml/output.txt
Original file line number Diff line number Diff line change
@@ -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
15 changes: 14 additions & 1 deletion src/core/etl/src/Flow/ETL/Function/DOMElementAttributeValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
14 changes: 13 additions & 1 deletion src/core/etl/src/Flow/ETL/Function/DOMElementValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
17 changes: 17 additions & 0 deletions src/core/etl/src/Flow/ETL/Function/Parameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace Flow\ETL\Tests\Integration\Function;

use function Flow\ETL\DSL\{df, from_rows, ref, row, rows, xml_element_entry, xml_entry};
use Flow\ETL\Adapter\Elasticsearch\Tests\Integration\TestCase;

final class DOMElementAttributeValueTest extends TestCase
{
public function test_dom_element_attribute_value() : void
{
$rows = df()
->read(from_rows(
rows(
row(
xml_element_entry('node', '<name id="1">User Name 01</name>')
)
)
))
->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', '<name id="1">User Name 01</name>')
)
)
))
->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 id="1">User Name 01</name></user>')
)
)
))
->withEntry('user_id', ref('node')->xpath('name')->domElementAttributeValue('id'))
->drop('node')
->fetch();

self::assertSame(
[
['user_id' => '1'],
],
$rows->toArray()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace Flow\ETL\Tests\Integration\Function;

use function Flow\ETL\DSL\{df, from_rows, ref, row, rows, xml_element_entry, xml_entry};
use Flow\ETL\Adapter\Elasticsearch\Tests\Integration\TestCase;

final class DOMElementValueTest extends TestCase
{
public function test_dom_element_value() : void
{
$rows = df()
->read(from_rows(
rows(
row(
xml_element_entry('node', '<name>User Name 01</name>')
)
)
))
->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', '<name>User Name 01</name>')
)
)
))
->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>User Name 01</name></user>')
)
)
))
->withEntry('user_name', ref('node')->xpath('name')->domElementValue())
->drop('node')
->fetch();

self::assertSame(
[
['user_name' => 'User Name 01'],
],
$rows->toArray()
);
}
}

0 comments on commit 9c0f8a5

Please sign in to comment.