In MigrateItemsXML::getIDsFromXML(…) the XPath expressions itemXpath and itemIDXpath get concatenated like this:
$full_xpath = $this->itemXpath . '/' . $this->itemIDXpath;
This can result in wrong behaviour. Consider this case:
$itemXpath = '/node_export/node[nid = tnid]/field_camp_images/*[not(@type)]' .
' | /node_export/node[nid = tnid]/field_camp_gallery_images/*[not(@type)]';
$itemIDXpath = 'fid';
$full_xpath = $itemXpath . '/' . $itemIDXpath;
// results in '/node_export/node[nid = tnid]/field_camp_images/*[not(@type)] | /node_export/node[nid = tnid]/field_camp_gallery_images/*[not(@type)]/fid'
In this case the wrong number of IDs gets reported.
Comments
Comment #1
Pisco commentedThe solution is to iterate over the elements (
itemXpath) and callgetItemID(…)to get the id. Funny enough it's done exactly like this ingetItemsFromXML(…).getIDsFromXML(…)andgetItemsFromXML(…)now look very similar, maybe we can reuse the code instead of duplicating it?Comment #2
Pisco commentedNote however, that you can work around this bug by using the following expression in my example:
Comment #3
mikeryanCommitted, thanks!
Comment #4
Pisco commentedI have to thank you for an absolutely awesome module! Thank you!
I noticed that you maybe accidentally committed the patch file itself (fix-xpath-handling-1054616-1.patch).
How about code reuse of
getItemsFromXML(…)(see my question above)? I think it would be much more robust and maintainable ifgetIDsFromXML(…)would callgetItemsFromXML(…). They do essentially the same. Performance wise I think it wouldn't be much of a tradeoff.Comment #5
drewish commentedYou don't need the call to array_unique() any more:
because keys are unique by definition.
Comment #6
drewish commentedBut I'm not sure it makes sense to separate them out... or if you're going to go that way we should drop the getItemID() functions.
Comment #7
Pisco commented@drewish, I don't think I understand, what do you mean by “separate them out”? And why drop
getItemID(), because of the extra function call? I don't think you gain anything by dropping it.The patch improves maintainability and code reuse, nothing more.
Comment #8
drewish commentedYeah I missing that getItemID() was used by getItemsFromXML(). But I think the current process makes more sense that potentially bundling up a huge number of items just to have the caller discard them and pull the keys back out.
Comment #9
Pisco commentedAs you like of course. Thanks for looking into it!
I think the issue can be considered fixed now.
Comment #11
twodThe patch in #1 broke the item xpath for me when the document uses a default namespace, such as in Google's KML files:
I explicitly registered the namespace and assigned it a prefix, which is needed becuase SimpleXML doesn't do default namespaces, and I used that prefix in the item and item-id xpaths. The setup code was almost identical to that of the OP in #1290706: MigrateItemsXML: Centralize loading of XML.
It did work before this change because my xpaths were simple enough to be concatenated, as demonstrated in the OP, and Migrate did not run another XPath query on the element(s) returned from a previous query.
As noted in the SimpleXMLElement::registerXPathNamespace documentation, that method only "creates a prefix/ns context for the next XPath query".
The namespaces need to be re-registered on each element returned from an XPath query.
In my use case, the problem first emerged in the below snippet, when fetching a list of ids to count the records to import.
It always returned an empty result because
$xmlcontained a SimpleXMLElement gotten from a previous XPath query, and the namespaces were no longer registered. ($xmlstill keeps track of the default namespace, and$this->itemXpathdid contain the prefix, but the prefix was no longer registered to that namespace.)My solution was to allow the creator of the MigrateItemsXML class to pass in a list of prefix/namespaces that should be automatically re-registered on the elements returned from an XPath query, as shown in the patch. I can now use my registered prefix like this:
Note: I've not looked at if something needs to be done about the class(es) handling sources which do not have the item and id together.
Comment #12
mikeryanPlease don't reopen long-closed issues, particularly when you're proposing a complex patch that's only tangentially related - please open a fresh issue for handling namespaces in MigrateListXML/MigrateItemsXML.
Comment #13
windmaomao commented#11 can address answers on https://drupal.org/node/1961316
I'll try #11's solution, basically i have the same issue.