tags:

views:

72

answers:

2

Hi,

I have an XML File like :

<company>
  <dept>
    <name> Dept-A</name>
    <proj> 
      <id> A1 </id>
      <noOfPeople> 5 </noOfPeople>
      <proj> 
        <id>A11</id>
        <noOfPeople> 2 </noOfPeople>
      </proj>
    </proj>
  </dept>
  <dept>
      ....
  </dept>
</company>

Now:

  1. I want to have a list of all the projects. Even if they are Sub Projects like A11 inside A1, I want every distinct proj id.
  2. Also, I want to have this list available to me at multiple locations, Ex. While parsing project A1, or while parsing A11 or any other nesting level of proj.

Is there any way of achieving this in XSLT?

Thank You.
Tara Singh

+1  A: 

Yes, this is possible.

The following XPath expression will select all proj elements in the document:

//proj
Kragen
+3  A: 
  1. I want to have a list of all the projects. Even if they are Sub Projects like A11 inside A1, I want every distinct proj id.

  2. Also, I want to have this list available to me at multiple locations, Ex. While parsing project A1, or while parsing A11 or any other nesting level of proj.

Is there any way of achieving this in XSLT?

You haven't specified whether it is possible to have more than one <proj> element with the same value of its child <id>.

Here is an XSLT solution that defines two global variables, one the node-set of all <id> elements in the XML document, the other -- a node-set of <id> elements each of which has a value that is different from the values of the rest and all values of <id>s are sepresented.

As these are global variables, they are accessible at any point of your XSLT code, even in imported/included or importing/including stylesheets.

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kIdByVal" match="id" use="."/>

 <xsl:variable name="vallProjIds" select="//proj/id"/>

 <xsl:variable name="vdistinctProjIds" select=
  "//proj/id[generate-id()
            =
             generate-id(key('kIdByVal', .)[1])
            ]
  "/>

 <xsl:template match="/">
  All Project IDs:
  <xsl:for-each select="$vallProjIds">
    <xsl:value-of select="concat(.,'&#xA;')"/>
  </xsl:for-each>
  All Distinct Project IDs:
  <xsl:for-each select="$vdistinctProjIds">
    <xsl:value-of select="concat(.,'&#xA;')"/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document (based on the provided one, but made well-formed and extended to cover more cases):

<company>
  <dept>
    <name> Dept-A</name>
    <proj>
      <id> A1 </id>
      <noOfPeople> 5 </noOfPeople>
      <proj>
        <id>A11</id>
        <noOfPeople> 2 </noOfPeople>
      </proj>
    </proj>
  </dept>
  <dept>
    <name> Dept-B</name>
    <proj>
      <id> A1 </id>
      <noOfPeople> 5 </noOfPeople>
    </proj>
    <proj>
      <id> B1 </id>
      <noOfPeople> 5 </noOfPeople>
      <proj>
        <id>B11</id>
        <noOfPeople> 2 </noOfPeople>
      </proj>
    </proj>
  </dept>
</company>

the wanted, correct result is produced:

  All Project IDs:
   A1 
   A11
   A1 
   B1 
   B11

  All Distinct Project IDs:
   A1 
   A11
   B1 
   B11

Do note that this solution uses the Muenchian method for grouping in order to obtain the set of Id s with unique values.

Dimitre Novatchev
@Dimitre: +1 Good answer and explanation.
Alejandro
Thank you for the detailed explanation. This clears many of my doubts.
Tara Singh