[xsl] Inheriting an attribute from first ancestor that defines it

Subject: [xsl] Inheriting an attribute from first ancestor that defines it
From: "Sean O'Halpin" <seanohalpin@xxxxxxxxxxx>
Date: Fri, 25 Oct 2002 17:27:34 +0100
Hello,

XSLT newbie warning! :)

I apologise in advance if this question has been answered before. I tried
searching the list on "inherit attribute" (and numerous variations) but had
no luck.

I apologise also for the length of this post - but one thing I've learnt in
the couple of weeks I've been doing XSLT is that if you can't tolerate
longwinded then it ain't for you ;)

Anyway, here's my problem:

I'd like to have child elements inherit an attribute from the first ancestor
in their ancestry that defines it.

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[@id=2] and page[@id=3] to inherit @style from page[@id=1],
page[@id=4] to inherit @style from page[@id=0], page[@id=6] to inherit from
page[@id=5], and page[@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[@id=3] has now inherited @style from the outermost
ancestor that defines a style attribute (page[@id=0), which is not what I
want - I want it to inherit from page[@id=1].

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


Current Thread