xsl-list
[Top] [All Lists]

RE: Inheriting an attribute from first ancestor that defines it

2002-10-25 11:14:17
I'd like to have child elements inherit an attribute from the 
first ancestor in their ancestry that defines it.

(ancestor::*/@att)[last()]

Note the brackets, because you want the last of all the attributes, not
the last attribute of a particular ancestor. Note also that it's the
last (in document order) not the first.

The above selects the attribute, if you want to select the element, use

ancestor::*[(_at_)att][last()]

Michael Kay
Software AG
home: Michael(_dot_)H(_dot_)Kay(_at_)ntlworld(_dot_)com
work: Michael(_dot_)Kay(_at_)softwareag(_dot_)com 


Specifically, is there a more general way (than specifying 
test="../@attr",
test="../../@attr") to select the first ancestor travelling 
back up the tree that defines a specific attribute?

This is my example xml doc:

<?xml version="1.0" encoding="utf-8"?>
<doc style="doc">
  <page id="0" style="default">
    <page id="1" style="page1">
      <page id="2">
        <page id="3"/>
      </page>
    </page>
    <page id="4">
      <page id="5" style="page5">
        <page id="6"/>
        <page id="7" style="page7"/>
      </page>
    </page>
  </page>
</doc>

Please note that the ids are just for reference here - I 
don't want to refer to them in the stylesheet.

I'd like page[(_at_)id=2] and page[(_at_)id=3] to inherit @style from 
page[(_at_)id=1], page[(_at_)id=4] to inherit @style from page[(_at_)id=0], 
page[(_at_)id=6] to inherit from page[(_at_)id=5], and page[(_at_)id=7] to 
use its own @style attribute.

In other words, I'd like the following output:

<?xml version="1.0" encoding="utf-8"?><doc style="doc">
  <page id="0" style="default">
    <page id="1" style="page1">
      <page id="2" style="page1">
        <page id="3" style="page1"></page>
      </page>
    </page>
    <page id="4" style="default">
      <page id="5" style="page5">
        <page id="6" style="page5"></page>
        <page id="7" style="page7"></page>
      </page>
    </page>
  </page>
</doc>

Now, this stylesheet works for my particular example (with 
the above level of nesting):

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version = '1.0' 
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>

<xsl:output method="xml" encoding="utf-8"/>

<xsl:template match="/">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="//page">

  <page>
    <xsl:copy-of select="@*"/>

    <xsl:attribute name="style">
      <xsl:choose>
        <xsl:when test="@style">
          <xsl:value-of select="@style"/>
        </xsl:when>
        <!-- parent's attribute -->
        <xsl:when test="../@style">
          <xsl:value-of select="../@style"/>
        </xsl:when>
        <!-- grandparent's attribute -->
        <xsl:when test="../../@style">
          <xsl:value-of select="../../@style"/>
        </xsl:when>
        <!-- ancestor's attribute -->
        <xsl:otherwise>
          <xsl:value-of select="ancestor::*/@style"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>

    <xsl:apply-templates/>

  </page>

</xsl:template>


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

</xsl:stylesheet>

But if I add more levels of nesting, I have to define further 
rules to match ../../../, etc.

My problem with "ancestor::*/@style" is that it selects the 
outermost ancestor's attribute.

For example, if I remove the selector for the grandparent's 
attribute, I get the following:

<?xml version="1.0" encoding="utf-8"?><doc>
  <page id="0" style="default">
    <page id="1" style="page1">
      <page id="2" style="page1">
        <page id="3" style="default"></page>
      </page>
    </page>
    <page id="4" style="default">
      <page id="5" style="page5">
        <page id="6" style="page5"></page>
        <page id="7" style="page7"></page>
      </page>
    </page>
  </page>
</doc>

You'll note that page[(_at_)id=3] has now inherited @style from 
the outermost ancestor that defines a style attribute 
(page[(_at_)id=0), which is not what I want - I want it to inherit 
from page[(_at_)id=1](_dot_)

Thanks in advance for any help you can offer.

Regards,

Sean O'Halpin

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list




 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list