views:

100

answers:

2

I'm in a situation where I can only test for the child node, but I have to apply tags to the grandparent of this child node.

I've tried using:

<xsl:call-template name="grandparent" select="parent::parent::node()"/>

and:

<xsl:call-template name="grandparent" select="ancestor::node [@nameofgrandparentnode]"/>

But neither works.

The level of the grandparent node is not fixed, so I figure I can't use [@level=#] either. Any ideas on how to select it would be greatly appreciated.

EDIT: -- This part has been posted as a new question:

http://stackoverflow.com/questions/3687466/xslt-select-grandparent-node-depending-on-an-attribute-value-of-its-grandchild-no

Selecting the node using the suggestions from below worked. Thanks! However I also need to test by the attribute of the grandparent or grandchild node.

I've tried:

<xsl:template name"one" match="grandparentnode">
 <Tag1>
  <xsl:apply-templates select="parentNode" />
 </Tag1>
</xsl:template>

<xsl:template name="two" match="grandparentnode[*/*/@grandchildattr='attrValue']">
 <Tag2>
     <xsl:apply-templates select="parentNode" />
 </Tag2>
</xsl:template>

However template "two" always gets called, and "" is always inserted. Even for grandchild nodes whose attribute value is not equal to 'attrValue'.

Am I missing something here?

+4  A: 

I've tried using:

<xsl:call-template name="grandparent"

select="parent::parent::node()"/>

and:

<xsl:call-template name="grandparent"

select="ancestor::node [@nameofgrandparentnode]"/>

But neither works.

Certainly it will not "work", because the <xsl:call-template> instruction doesn't have a select attribute!

You may pass parameters using <xsl:with-param> children of the <xsl:call-template> instruction, like this:

<xsl:call-template name="compute">
  <xsl:param name="pAncestor" select="someExpression"/>
</xsl:call-template>

For the select attribute of the <xsl:with-param> Use:

For a real grandparent:

../..

for the closest ancestor element with name someName:

ancestor::someName[1]

for the closest ancestor element with name contained in the variable $ancName:

ancestor::*[name()=$ancName][1]
Dimitre Novatchev
@Dimitre: +1 for abbreviate gradparent XPath expression.
Alejandro
<xsl:with-param> worked - thanks!
highlightall
@highlightall: Glad it worked. Here at SO gratitude is expressed by accepting an answer. Hint: Just click on the check-mark next to the answer. :)
Dimitre Novatchev
Cool, just did that :) Any suggestions for the edited part of the question on testing for grandchildren's attributes?
highlightall
@Dimitre: I've posted a new question on the edit: http://stackoverflow.com/questions/3687466/xslt-select-grandparent-node-depending-on-an-attribute-value-of-its-grandchild-no
highlightall
+3  A: 
Bert F
@Bert F: +1 for good answer and explanation about correct approach.
Alejandro
@Alejandro - Thanks - check out those test resources - I find them extremely convenient and useful for experimenting.
Bert F
Very useful code example. Thanks!
highlightall
@highthlightall - Thanks! Note that I updated the stylesheet to fix some sloppy (lazy) code. The apply-templates line the 2nd template should have been to be split to process attributes separate from child elements (so that new attributes and elements could be added at the proper times). Fixed now.
Bert F
@Bert F: If you really want to pretify yuor stylesheet then you should use literal result elements like: `<album new-attribute="A Capitol Record">`
Alejandro
@Alejandro - true, but I prefer the more general approach just in case (1) you want to apply the `xsl:template` to multiple matched elements, e.g. `album[...]|single[...]` and keep/copy what was matched, and (2) `album` might have attributes we want to keep/copy in addition to adding a new attribute.
Bert F