Search code examples
xmlxsltxpathxslt-grouping

handling the child tags in XSLT when the order of occurance is not specified


I am working on XSLT transformations. I have a source file where I have sometag called tag.

Consider my source xml to be like this.

<ABC>
    <Name>Some Name </Name>
    <ID>Some ID</ID>
    <Address>Some Address</Address>
    <Place>Some Place</Place>
    <ID>Some ID</ID>
    <Name>Some Name </Name>
    <Name>Some Name </Name>     

</ABC>

Rules:

  ABC is parent Tag which has 4 child tags. Name, ID, Address, Place. 
  These child tags can occur many times and in any ordrer.
  Upon reading the tag , I want to change the name of the tag, and do some processing on the value present in the tag.
  The input XML may have child tags in any order, and many times.
  I want to write a common XSLT which will read the child tags in the order in which they occur, and display them as given under.

I want to display the output like this.

        <Frame:Name>
                   <text>Some Name</text>
        </Frame:Name>
   <Frame:ID>
                   <text>Some ID</text>
        </Frame:ID>
        <Frame:ADdrress>
                   <text>Some Address</text>
        </Frame:Address>
        <Frame:Place>
                   <text>Some Place</text>
        </Frame:Place>
   <Frame:ID>
                   <text>Some ID</text>
        </Frame:ID>
       <Frame:Name>
                   <text>Some Name</text>
        </Frame:Name>
       <Frame:Name>
                   <text>Some Name</text>
        </Frame:Name>

I am completely struck how it can be done.

If the order of occurrence of child elements changes in Source XML it should also reflect in output XML.

Can some one share reviews on it.

Thank you.


Solution

  • The XSLT way to solve such problems is by using templates. The result is much simpler, shorter and understandable code, usually without any xsl:choose, xsl:when, xsl:otherwise, xsl:if or xsl:for-each:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:Frame="some:undefined namespace">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:template match="/*">
       <t><xsl:apply-templates/></t>
     </xsl:template>
    
     <xsl:template match="*/*">
         <xsl:element name="Frame:{name()}" namespace="some:undefined namespace">
           <text><xsl:apply-templates /></text>
         </xsl:element>
     </xsl:template>
    </xsl:stylesheet>
    

    When this transformation is applied on the provided XML document:

    <ABC>
        <Name>Some Name </Name>
        <ID>Some ID</ID>
        <Address>Some Address</Address>
        <Place>Some Place</Place>
        <ID>Some ID</ID>
        <Name>Some Name </Name>
        <Name>Some Name </Name>
    </ABC>
    

    the wanted, correct result is produced:

    <t xmlns:Frame="some:undefined namespace">
       <Frame:Name>
          <text>Some Name </text>
       </Frame:Name>
       <Frame:ID>
          <text>Some ID</text>
       </Frame:ID>
       <Frame:Address>
          <text>Some Address</text>
       </Frame:Address>
       <Frame:Place>
          <text>Some Place</text>
       </Frame:Place>
       <Frame:ID>
          <text>Some ID</text>
       </Frame:ID>
       <Frame:Name>
          <text>Some Name </text>
       </Frame:Name>
       <Frame:Name>
          <text>Some Name </text>
       </Frame:Name>
    </t>