There are 3 scenarios in this problem:
First possibility:
Input:
<root>
<node id="N1">
<fruit id="1" action="aaa">
<orange id="x" action="create">
<attribute>
<color>Orange</color>
<year>2012</year>
</attribute>
</orange>
<orange id="x" action="change">
<attribute>
<color>Red</color>
</attribute>
</orange>
<orange id="x" action="change">
<attribute>
<color>Blue</color>
<condition>good</condition>
</attribute>
</orange>
</fruit>
</node>
</root>
Expected output:
<root>
<node id="N1">
<fruit id="1" action="aaa">
<orange id="x" action="create">
<attribute>
<color>Blue</color>
<year>2012</year>
<condition>good</condition>
</attribute>
</orange>
</fruit>
</node>
</root>
Second Possibility:
Input:
<root>
<node id="N1">
<car id="1">
<bmw id="i" action="change">
<attribute>
<color>Blue</color>
<owner>a</owner>
</attribute>
</bmw>
<bmw id="i" action="change">
<attribute>
<color>Yellow</color>
<status>avaailable</status>
</attribute>
</bmw>
</car>
</node>
</root>
Expected Output:
<root>
<node id="N1">
<car id="1">
<bmw id="i" action="change">
<attribute>
<color>Yellow</color>
<owner>a</owner>
<status>available</status>
</attribute>
</bmw>
</car>
</node>
</root>
Third Scenario:
<root>
<node id="N1">
<car id="1">
<bmw id="j" action="delete">
<attribute>
<color>Blue</color>
<year>2000</year>
</attribute>
</bmw>
<bmw id="j" action="delete">
<attribute>
<color>Pink</color>
<status>available</status>
</attribute>
</bmw>
</car>
</node>
</root>
Expected Output:
<root>
<node id="N1">
<car id="1">
<bmw id="j" action="delete">
<attribute>
<color>Pink</color>
<year>2000</year>
<status>available</status>
</attribute>
</bmw>
</car>
</node>
</root>
Explanation on second and third scenario:
- Two or more node with ‘action=change’ will be merged into one node with ‘action=change’
- Two or more node with ‘action=delete’ will be merged into one node with ‘action=delete’
- while merging, we update we only keep the value from the last node, keep the initial node and add any new additional node with it.
I hope the explanation is clear.
Please advise me on XSLT solution for this problem.
Thank you.
kind regards,
John
Here’s a solution of a different flavor compared to the one I gave you here.
I figured it would be worth to go step by step. I made an assumption about
@actions appearing in a logical order –createfirst,changenext, andremovelast. There can be multiple occurrences of the same@actionbut it wouldn’t be random. Now we’re ready to look at the main logic:We declare the identity transformation and then intercept it in a few places. We only stop at unique occurrences of a node with the same
@id, parent@id, and@action:We ignore the “duplicates”:
and also ignore
creates following by achangeas well as allcreates andchangefollowed by aremove.When the unique
@actionnot followed by another@actionthat would make us ignore it is captured, we do a simple thing – collect all attributes of elements with the same@ids ignoring the@actionand use their most “recent” values (the ones appearing last in the document order).That’s it. Now let’s look at the functions that would make it work:
We have got a
keyto simplify the lookupA function to check whether it’s that unique occurrence of the node (we could add this directly into the template
matchpredicate but since we started with the functions anyway let’s just keep it the same):a
matchesfunction that will do all kind of comparisons for us (again, can put it all in predicates but this way we’ll keep it nice and clean in the real templates):And the
preceded-byandfollowed-bysyntax sugar on top of the “raw”matchesfunction:SUMMARY
Here’s a full transformation:
when applied to a document:
produces the following result:
I hope it’s clear. You can expand on this concept and build yourself a nice library of those reusable functions that you would then use as simple predicates merging your nodes one way or the other. Unlikely to be the most effective way to do the job but at least a clean way to express the solution.