Reputation: 9
I'm new to xslt and it would be really helpful if anyone could help me with this problem. I have a XML document which looks something like this,
<ParentElement>
<ChildElement name = "xxx" place = "yyy">
<GrandChildElement parameter1 = "a" parameter2 = "b">
</GrandchildElement>
<GrandChildElement parameter1 = "c" parameter2 = "d">
</GrandchildElement>
</ChildElement>
<ChildElement name = "xxx" place = "yyy">
<GrandChildElement parameter1 = "a" parameter2 = "x">
</GrandchildElement>
<GrandChildElement parameter1 = "c" parameter2 = "y">
</GrandchildElement>
</ChildElement>
</ParentElement>
I want to assign a unique id to each child element and to each grandchilds. The output that I want should be something like this,
<ParentElement>
<ChildElement>
<Child_ID>100</Child_ID>
<Name></Name>
<GrandChild>
<id>200</id>
<Label></Label>
</GrandChild>
<GrandChild>
<id>201</id>
<Label></Label>
</GrandChild>
<GrandChild>
<id>202</id>
<Label></Label>
</GrandChild>
</ChildElement>
<ChildElement>
<Child_ID>101</Child_ID>
<Name></Name>
<GrandChild>
<id>203</id>
<Label></Label>
</GrandChild>
<GrandChild>
<id>204</id>
<Label></Label>
</GrandChild>
</ChildElement>
</ParentElement>
I used something this to create the ids for the Child elements which was successful.
<xsl:for-each select="ChildElement">
<xsl:variable name="i" select="1" />
<xsl:variable name="j" select="$i + position()"/>
<xsl:element name = "ChildElement">
<xsl:element name = "Id">DT-<xsl:value-of select="200 + $j"/></xsl:element>
</xsl:for-each>
what can I do to get a different id for every grand child?
Upvotes: 0
Views: 63
Reputation: 1235
So, if you are looking for the pattern you showed in your input XML, this may be one approach. You have to consider what happens when you have more than 100 ChildElement elements. Just play with your offsets. This approach may be useful if you don't want letters in your id. Or your are dealing with multiple XMLs. Just pass a parameter to your XSLT file with your unique starting offset.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt">
<xsl:output indent="yes"/>
<xsl:variable name="childIDs">
<xsl:for-each select="//ChildElement">
<xsl:element name="element">
<xsl:element name="id">
<xsl:value-of select="generate-id(.)"/>
</xsl:element>
<xsl:element name="outid">
<xsl:value-of select="position() + 100"/>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:variable>
<!-- For 1.0 use your own prefix here. It may not be msxml. -->
<xsl:variable name="childIDList" select="msxml:node-set($childIDs)"/>
<xsl:variable name="grandchildIDs">
<xsl:for-each select="//GrandChildElement">
<xsl:element name="element">
<xsl:element name="id">
<xsl:value-of select="generate-id(.)"/>
</xsl:element>
<xsl:element name="outid">
<xsl:value-of select="position() + 200"/>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:variable>
<!-- For 1.0 use your own prefix here. It may not be msxml. -->
<xsl:variable name="grandchildIDList" select="msxml:node-set($grandchildIDs)"/>
<xsl:template match="ChildElement">
<xsl:variable name="id" select="generate-id(.)"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:element name="Child_ID">
<xsl:value-of select="$childIDList/element[id = $id]/outid"/>
</xsl:element>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GrandChildElement">
<xsl:variable name="id" select="generate-id(.)"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:element name="id">
<xsl:value-of select="$grandchildIDList/element[id = $id]/outid"/>
</xsl:element>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 117165
XSLT has a built-in function for generating a unique id for each node in the input XML. Consider the following example:
XML
<ParentElement>
<ChildElement name = "xxx" place = "yyy">
<GrandChildElement parameter1 = "a" parameter2 = "b"/>
<GrandChildElement parameter1 = "c" parameter2 = "d"/>
</ChildElement>
<ChildElement name = "xxx" place = "yyy">
<GrandChildElement parameter1 = "a" parameter2 = "x"/>
<GrandChildElement parameter1 = "c" parameter2 = "y"/>
</ChildElement>
</ParentElement>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="ParentElement">
<xsl:copy>
<xsl:for-each select="ChildElement">
<xsl:copy>
<Child_ID>
<xsl:value-of select="generate-id()"/>
</Child_ID>
<xsl:for-each select="GrandChildElement">
<GrandChild>
<id>
<xsl:value-of select="generate-id()"/>
</id>
</GrandChild>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The exact result varies from one processor to another. For example, libxslt
may return a result like:
<?xml version="1.0" encoding="UTF-8"?>
<ParentElement>
<ChildElement>
<Child_ID>idm49868912656</Child_ID>
<GrandChild>
<id>idm49868912048</id>
</GrandChild>
<GrandChild>
<id>idm49868911344</id>
</GrandChild>
</ChildElement>
<ChildElement>
<Child_ID>idm49868910448</Child_ID>
<GrandChild>
<id>idm49868909744</id>
</GrandChild>
<GrandChild>
<id>idm49868909008</id>
</GrandChild>
</ChildElement>
</ParentElement>
while Xalan
will produce a result like:
<?xml version="1.0" encoding="UTF-8"?><ParentElement>
<ChildElement>
<Child_ID>N10004</Child_ID>
<GrandChild>
<id>N10008</id>
</GrandChild>
<GrandChild>
<id>N1000C</id>
</GrandChild>
</ChildElement>
<ChildElement>
<Child_ID>N10011</Child_ID>
<GrandChild>
<id>N10015</id>
</GrandChild>
<GrandChild>
<id>N10019</id>
</GrandChild>
</ChildElement>
</ParentElement>
Upvotes: 1