Reputation: 118
Using XSLT, I am trying to figure out how to merge/update the data in a set of nodes with data from another set of nodes. The nodes have the same schema, but different parents. The data needs to be merged based on a shared parent attribute. In the example below, data is being copied from Principal to Driver. Can anyone help me out here?
Input File:
<Info>
<Principal id="Insured">
<PersonName>
<GivenName>Jane</GivenName>
<OtherGivenName>A</OtherGivenName>
<Surname>Doe</Surname>
</PersonName>
<PersonInfo>
<BirthDate>01-01-1980</BirthDate>
<MaritalStatus>M</MaritalStatus>
</PersonInfo>
<PrincipalInfo></PrincipalInfo>
</Principal>
<Policy>
<Driver id="Insured">
<PersonName>
<GivenName>Jane</GivenName>
<Surname>Smith</Surname>
</PersonName>
<PersonInfo>
<BirthDate>01-01-1980</BirthDate>
<MaritalStatus>S</MaritalStatus>
<Occupation>Manager</Occupation>
</PersonInfo>
</Driver>
<PolicyInfo></PolicyInfo>
</Policy>
</Info>
Desired Result:
<Info>
<Principal id="Insured">
<PersonName>
<GivenName>Jane</GivenName>
<OtherGivenName>A</OtherGivenName>
<Surname>Doe</Surname>
</PersonName>
<PersonInfo>
<BirthDate>01-01-1980</BirthDate>
<MaritalStatus>M</MaritalStatus>
</PersonInfo>
<PrincipalInfo></PrincipalInfo>
</Principal>
<Policy>
<Driver id="Insured">
<PersonName>
<GivenName>Jane</GivenName>
<OtherGivenName>A</OtherGivenName>
<Surname>Doe</Surname>
</PersonName>
<PersonInfo>
<BirthDate>01-01-1980</BirthDate>
<MaritalStatus>M</MaritalStatus>
<Occupation>Manager</Occupation>
</PersonInfo>
</Driver>
<PolicyInfo></PolicyInfo>
</Policy>
</Info>
Upvotes: 2
Views: 1309
Reputation: 243459
Here is a complete solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPrincipalById" match="Principal"
use="@id"/>
<xsl:key name="kPrincipalChild" match="Principal/*/*"
use="concat(../../@id, name())"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Driver/*">
<xsl:variable name="vPrincipal"
select="key('kPrincipalById', ../@id)"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select=
"$vPrincipal/*[name()=name(current())]/*"/>
<xsl:apply-templates select=
"*[not(key('kPrincipalChild',
concat(../../@id,name())
)
)
]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<Info>
<Principal id="Insured">
<PersonName>
<GivenName>Jane</GivenName>
<OtherGivenName>A</OtherGivenName>
<Surname>Doe</Surname>
</PersonName>
<PersonInfo>
<BirthDate>01-01-1980</BirthDate>
<MaritalStatus>M</MaritalStatus>
</PersonInfo>
<PrincipalInfo></PrincipalInfo>
</Principal>
<Policy>
<Driver id="Insured">
<PersonName>
<GivenName>Jane</GivenName>
<Surname>Smith</Surname>
</PersonName>
<PersonInfo>
<BirthDate>01-01-1980</BirthDate>
<MaritalStatus>S</MaritalStatus>
<Occupation>Manager</Occupation>
</PersonInfo>
</Driver>
<PolicyInfo></PolicyInfo>
</Policy>
</Info>
the wanted, correct result is produced:
<Info>
<Principal id="Insured">
<PersonName>
<GivenName>Jane</GivenName>
<OtherGivenName>A</OtherGivenName>
<Surname>Doe</Surname>
</PersonName>
<PersonInfo>
<BirthDate>01-01-1980</BirthDate>
<MaritalStatus>M</MaritalStatus>
</PersonInfo>
<PrincipalInfo/>
</Principal>
<Policy>
<Driver id="Insured">
<PersonName>
<GivenName>Jane</GivenName>
<OtherGivenName>A</OtherGivenName>
<Surname>Doe</Surname>
</PersonName>
<PersonInfo>
<BirthDate>01-01-1980</BirthDate>
<MaritalStatus>M</MaritalStatus>
<Occupation>Manager</Occupation>
</PersonInfo>
</Driver>
<PolicyInfo/>
</Policy>
</Info>
Explanation:
The identity rule/template copies every node "as-is". The use and overriding of the identity rule is the most fundamental and powerful XSLT design pattern.
There is just one additional template that overrides the identity rule for children-elements of Driver
. It copies (and effectively replaces the same-named grand-child elements of Driver
with the corresponding) grand-child elements of Principal
. Then it still processes (copies) those grand-children elements of Driver
that do not have corresponding grand-children elements of Principal
For convenient access to Principal
and its grand-children -- by id and id++name(), there are two keys defined and used.
Upvotes: 2