If a direct child of the item_selector has multiple values and those values are not strings, only a single value is preserved and passed to any process plugins.
From Drupal\migrate_plus\Plugin\migrate_plus\data_parser\Xml::fetchNextRow() ~ line 249
// If the SimpleXMLElement doesn't render to a string of any sort,
// 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; // The culprit
}
else {
$this->currentItem[$field_name][] = (string) $value;
}
Fix:
// If the SimpleXMLElement doesn't render to a string of any sort,
// 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; // Match the else, preserve all values.
}
else {
$this->currentItem[$field_name][] = (string) $value;
}
Source XML:
<Categories>
<Category>
<Code>category_1</Code>
<Name>Category 1</Name>
<Items1>
<SubItem>
<Id>1</Id>
<Name>Name 1</Name>
</SubItem>
<SubItem>
<Id>2</Id>
<Name>Name 2</Name>
</SubItem>
</Items1>
<Items2>
<SubItem>1</SubItem>
<SubItem>2</SubItem>
</Items2>
</Category>
</Categories>
Migration template:
id: test_migration
migration_group: test
source:
plugin: url
urls: 'private://categories.xml'
data_fetcher_plugin: file
data_parser_plugin: xml
item_selector: /Categories/Category
ids:
code:
type: string
fields:
-
name: code
label: 'Code'
selector: 'Code'
-
name: name
label: 'Name'
selector: 'Name'
-
name: sub_items1
label: 'Sub items 1'
selector: 'Items1/SubItem'
-
name: sub_items2
label: 'Sub items 2'
selector: 'Items2/SubItem'
process:
vid:
plugin: default_value
default_value: test
name: name
destination:
plugin: entity:taxonomy_term
For fields which have one level selector (like sub_items2) it works fine. But for fields with several children and complex structure like sub_items1 it's returning only last element.
Comment | File | Size | Author |
---|---|---|---|
#6 | xml-parser-condensing-multiple-values--3028162-4.patch | 1.38 KB | DuaelFr |
#6 | interdiff-3028162-2-6.txt | 724 bytes | DuaelFr |
Issue fork migrate_plus-3028162
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
sonfdComment #3
sonfdComment #4
sonfdComment #5
hctomComment #6
DuaelFrThe same issue exists in the SimpleXml parser.
Comment #7
Raphael Apard CreditAttribution: Raphael Apard commentedWorks great for me
Comment #8
MatroskeenThank you for the patch!
Do you think we can add a unit test to make sure it's not broken again?
As I see, we already have a bunch of XML tests. Let's push it back to "Needs Work" and see if we can add some :)
Thanks!
Comment #9
MatroskeenBy the way, we have some test examples in the related issue: #2986883: Xml data_parser reducing single-value results to scalar for SimpleXMLElements.
Comment #11
MatroskeenI'm adding XML examples from duplicated issue #3102400: XML data parser holds only value for last child and transferring an issue credit.
Comment #12
MatroskeenComment #16
MatroskeenCommitted to 6.0.x and cherry-picked to 8.x-5.x.
Thanks!
Comment #17
MatroskeenAdding a missing credit :)