Amine Mchayaa
Amine Mchayaa

Reputation: 124

Get the name of the Grandparent of a node

I'm trying to transform an XML file and trying to test if a node's grandparent has a certain name but i don't know how to get to the grandparent name. this is the example I'm working on. what i tried to do is to get the parent and then find the parent of the parent but it didn't work.
thanks.

<?xml version="1.0" encoding="UTF-8"?>
    <breakfast_menu>
    <food_XX>
    <food_X>
    <food>
    <name>Belgian Waffles</name>
    </food>
    </food_X>
    </food_XX>

    <food_XX1>
    <food_X>
    <food>
    <name>Strawberry Belgian Waffles</name>
    </food>
    </food_X>
    </food_XX1>
    </breakfast_menu>

and this is the xsl code:

<?xml version="1.0" encoding="UTF-8"?>
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
<xsl:for-each select=".//food">
<xsl:variable name="parentName" select="parent::food_X" />
<xsl:value-of  select="name($parentName)" />
<xsl:if test="name(parent::$parentName)='food_XX1'">
<div style="background-color:teal;color:white;padding:4px">
<span style="font-weight:bold"><xsl:value-of select="name"/> - </span>
</div>
</xsl:if>
</xsl:for-each>
</body>
</html>

Upvotes: 0

Views: 1014

Answers (3)

Michael Kay
Michael Kay

Reputation: 163322

Even better, use template rules.

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<html>
  <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
    <xsl:apply-templates select=".//food">
  </body>
</html>
</xsl:template>

<xsl:template match="food"/>

<xsl:template match="food_XX1/*/food">
  <div style="background-color:teal;color:white;padding:4px">
   <span style="font-weight:bold"><xsl:value-of select="name"/> - </span>
  </div>
</xsl:template>

</xsl:transform>

Upvotes: 1

Mads Hansen
Mads Hansen

Reputation: 66723

The parent:: axis selects the parent of the context node.

In your example, the context node is the food element being processed inside the xsl:for-each. parent::food_X is the equivalent of ./parent::food_X

When you selected parent::food_X, it is attempting to select an element named food_X that is the parent of the context node (in this case, it is the food element). Then, when attempting to select the grandparent with parent::$parentName, was essentially saying, "give me the parent of this food element if it is a food_X element", rather than asking for the parent of food_X.

In order to find the parent of the $parentName, you need to use a step from $parentName, so that it looks for the parent of $parentName, and not the parent of the food element:

<xsl:if test="name($parentName/parent::*)='food_XX1'">

You could simplify your test further. Rather than selecting any parent element and then testing it's name, select the parent element food_XXX1:

<xsl:if test="$parentName/parent::food_XX1">

Even more simple, you could eliminate the $parentName variable from your XSLT and just use this:

<xsl:if test="parent::food_X/parent::food_XX1">

Upvotes: 1

Tim C
Tim C

Reputation: 70618

To find the parent name, you can just do this...

<xsl:if test="name(../..)='food_XX1'">

And for grandparents....

<xsl:if test="name(../..)='food_XX1'">

Note that, given your current XSLT, if the intention is just to output food nodes under food_XX1 you could re-write it as this....

<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
<xsl:for-each select=".//food_XX1/*/food">
   <div style="background-color:teal;color:white;padding:4px">
      <span style="font-weight:bold"><xsl:value-of select="name"/> - </span>
   </div>
</xsl:for-each>
</body>
</html>

Upvotes: 1

Related Questions