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
@action
s appearing in a logical order -create
first,change
next, andremove
last. There can be multiple occurrences of the same@action
but 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
create
s following by achange
as well as allcreate
s andchange
followed by aremove
.When the unique
@action
not followed by another@action
that would make us ignore it is captured, we do a simple thing - collect all attributes of elements with the same@id
s ignoring the@action
and 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
key
to simplify the lookupA function to check whether it's that unique occurrence of the node (we could add this directly into the template
match
predicate but since we started with the functions anyway let's just keep it the same):a
matches
function 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-by
andfollowed-by
syntax sugar on top of the "raw"matches
function: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.