tags:

views:

23

answers:

1

Hello, another XPath/XSL question :)

If i have a node tree like:

A

-- B (anymal-types=pets)

---- C (type=bird)

---- C (type=cat)

---- C (type=dog)

-- B (working-animals)

---- C (type=cow)

---- C (type=elephant)

-A
...

and another xml file ($xmlFile) that lists types that one needs for the given anymal-type

-pet

---- cat

---- dog

-working-animal

----elephant

how do i select only these animals that the $xmlFile oders me to?:

what in this case current() refers to: - is it node that template matches on ("A") - or is it current C node being evaluated.

What would be the right way to get to the current C node being evaluated and step one node up (to B, that defines animal-type).

Thanks.

A: 

This transformation:

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

    <xsl:variable name="vrtfXmlFile">
     <pets>
       <animal>cat</animal>
       <animal>dog</animal>
     </pets>
     <working-animals>
       <animal>elephant</animal>
     </working-animals>
    </xsl:variable>

    <xsl:variable name="vxmlFile" select=
     "document('')/*/xsl:variable
                      [@name='vrtfXmlFile']"/>

 <xsl:template match="node()|@*" name="identity">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="b">
   <xsl:if test="$vxmlFile/*[name()=current()/@animal-types]">
     <xsl:call-template name="identity"/>
   </xsl:if>
 </xsl:template>

 <xsl:template match="c">
  <xsl:if test=
    "$vxmlFile/*[name()=current()/../@animal-types]
                              /animal[.=current()/@type]">
   <xsl:call-template name="identity"/>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document:

<a>
 <b animal-types="pets">
   <c type="bird"/>
   <c type="cat"/>
   <c type="dog"/>
 </b>
 <b animal-types="working-animals">
   <c type="cow"/>
   <c type="elephant"/>
 </b>
</a>

produces the wanted, correct result:

<a>
   <b animal-types="pets">
      <c type="cat"/>
      <c type="dog"/>
   </b>
   <b animal-types="working-animals">
      <c type="elephant"/>
   </b>
</a>

Notes:

  1. For convenience, the second document containing the allowed animals, is incorporated in the XSLT stylesheet. In practice one would use the document(some-uri) function to read, parse and define this as the contents of the $vxmlFile variable.

  2. If the list of allowed animals is very long, then using Muenchian grouping (keys) would be significantly more efficient.

Dimitre Novatchev