From 88c4f71d3739d92d97679894d0a0c3c5faafed79 Mon Sep 17 00:00:00 2001
From: Matroskeen <matroskeen@3426249.no-reply.drupal.org>
Date: Sat, 21 May 2022 15:31:21 +0000
Subject: [PATCH] Issue #3028162 by Matroskeen, DuaelFr, p-andrei: XML Parser -
 multiple non-string values reduced to a single value

---
 .../migrate_plus/data_parser/SimpleXml.php    |  2 +-
 src/Plugin/migrate_plus/data_parser/Xml.php   |  2 +-
 tests/data/xml_multiple_items.xml             | 21 +++++++++++
 tests/data/xml_persons.xml                    | 32 ++++++++++++++++
 .../migrate_plus/data_parser/BaseXmlTest.php  | 37 ++++++++++++++++++-
 5 files changed, 91 insertions(+), 3 deletions(-)
 create mode 100644 tests/data/xml_multiple_items.xml
 create mode 100644 tests/data/xml_persons.xml

diff --git a/src/Plugin/migrate_plus/data_parser/SimpleXml.php b/src/Plugin/migrate_plus/data_parser/SimpleXml.php
index 5f86b8bc..49c08192 100644
--- a/src/Plugin/migrate_plus/data_parser/SimpleXml.php
+++ b/src/Plugin/migrate_plus/data_parser/SimpleXml.php
@@ -75,7 +75,7 @@ class SimpleXml extends DataParserPluginBase {
       foreach ($this->fieldSelectors() as $field_name => $xpath) {
         foreach ($target_element->xpath($xpath) as $value) {
           if ($value->children() && !trim((string) $value)) {
-            $this->currentItem[$field_name] = $value;
+            $this->currentItem[$field_name][] = $value;
           }
           else {
             $this->currentItem[$field_name][] = (string) $value;
diff --git a/src/Plugin/migrate_plus/data_parser/Xml.php b/src/Plugin/migrate_plus/data_parser/Xml.php
index 580df846..6090f330 100644
--- a/src/Plugin/migrate_plus/data_parser/Xml.php
+++ b/src/Plugin/migrate_plus/data_parser/Xml.php
@@ -243,7 +243,7 @@ class Xml extends DataParserPluginBase {
           // and has children then return the whole object for the process
           // plugin or other row manipulation.
           if ($value->children() && !trim((string) $value)) {
-            $this->currentItem[$field_name] = $value;
+            $this->currentItem[$field_name][] = $value;
           }
           else {
             $this->currentItem[$field_name][] = (string) $value;
diff --git a/tests/data/xml_multiple_items.xml b/tests/data/xml_multiple_items.xml
new file mode 100644
index 00000000..6f981683
--- /dev/null
+++ b/tests/data/xml_multiple_items.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<items>
+  <item>
+    <Id>item_1</Id>
+    <Name>Item 1</Name>
+    <Values1>
+      <SubItem>
+        <Id>1</Id>
+        <Name>Name 1</Name>
+      </SubItem>
+      <SubItem>
+        <Id>2</Id>
+        <Name>Name 2</Name>
+      </SubItem>
+    </Values1>
+    <Values2>
+      <SubItem>3</SubItem>
+      <SubItem>4</SubItem>
+    </Values2>
+  </item>
+</items>
diff --git a/tests/data/xml_persons.xml b/tests/data/xml_persons.xml
new file mode 100644
index 00000000..73d6559f
--- /dev/null
+++ b/tests/data/xml_persons.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<persons>
+  <person>
+    <id>1</id>
+    <name>Elizabeth</name>
+    <children>
+      <child age="8">
+        <name>Elizabeth Junior</name>
+        <name>Jane</name>
+      </child>
+    </children>
+  </person>
+  <person>
+    <id>2</id>
+    <name>George</name>
+    <children>
+      <child>
+        <name>George Junior</name>
+        <age>10</age>
+      </child>
+    </children>
+  </person>
+  <person>
+    <id>3</id>
+    <name>Peter</name>
+    <children>
+      <child>
+        <name age="6">Lucy</name>
+      </child>
+    </children>
+  </person>
+</persons>
diff --git a/tests/src/Kernel/Plugin/migrate_plus/data_parser/BaseXmlTest.php b/tests/src/Kernel/Plugin/migrate_plus/data_parser/BaseXmlTest.php
index 4e23038d..edb57dfe 100644
--- a/tests/src/Kernel/Plugin/migrate_plus/data_parser/BaseXmlTest.php
+++ b/tests/src/Kernel/Plugin/migrate_plus/data_parser/BaseXmlTest.php
@@ -117,7 +117,7 @@ abstract class BaseXmlTest extends KernelTestBase {
    */
   public function testSingleValueWithAttributes() {
     $urls = [
-      $this->path . '/tests/data/xml_data_parser.xml',
+      $this->path . '/tests/data/xml_persons.xml',
     ];
     $this->configuration['urls'] = $urls;
     $this->configuration['item_selector'] = '/persons/person';
@@ -143,6 +143,41 @@ abstract class BaseXmlTest extends KernelTestBase {
     $this->assertEquals($expected_names, $names);
   }
 
+  /**
+   * Tests retrieval a value with multiple items.
+   */
+  public function testMultipleItems(): void {
+    $this->configuration['urls'] = [
+      $this->path . '/tests/data/xml_multiple_items.xml',
+    ];
+    $this->configuration['fields'] = [
+      [
+        'name' => 'id',
+        'label' => 'Id',
+        'selector' => 'Id',
+      ],
+      [
+        'name' => 'sub_items1',
+        'label' => 'Sub items 1',
+        'selector' => 'Values1/SubItem',
+      ],
+      [
+        'name' => 'sub_items2',
+        'label' => 'Sub items 2',
+        'selector' => 'Values2/SubItem',
+      ],
+    ];
+
+    $parser = $this->getParser();
+    $parser->next();
+
+    // Transform SimpleXMLELements to arrays.
+    $item = json_decode(json_encode($parser->current()), TRUE);
+    $sub_items1 = array_column($item['sub_items1'], 'Id');
+    $this->assertEquals(['1', '2'], $sub_items1);
+    $this->assertEquals(['3', '4'], $item['sub_items2']);
+  }
+
   /**
    * Parses and asserts the results match expectations.
    *
-- 
GitLab