Kaya Choudhary
Kaya Choudhary

Reputation: 9

How to assign a unique id to the Parent, child and grandchild element?

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

Answers (2)

John Ernst
John Ernst

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

michael.hor257k
michael.hor257k

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

Related Questions