I think there may be a more efficient way to do this overall, but
certainly if you declare those @id attributes as ID, then you could
use the id() function. E.g.:
---------
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
<xsl:strip-space elements="*"/>
<xsl:template match="p">
<xsl:variable name="topicID" select="ancestor-or-self::*[@id][1]/@id"/>
<xsl:variable name="ancestors-in-topic"
select="ancestor-or-self::*[
ancestor-or-self::* intersect id($topicID)
]"/>
<xsl:copy>
<xsl:attribute name="topic" select="$topicID"/>
<xsl:text>Ancestors: </xsl:text>
<xsl:sequence select="$ancestors-in-topic/name()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="* | @*">
<xsl:copy>
<xsl:apply-templates select="@*, node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
---------
works iff you declare the @id attrs as type ID:
---------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE bars [
<!ELEMENT bars ( bar+ )>
<!ATTLIST bars id ID #IMPLIED>
<!ELEMENT bar ( bar | div )+>
<!ATTLIST bar id ID #IMPLIED>
<!ELEMENT div ( bar | div | p )+>
<!ELEMENT p EMPTY >
]>
<bars id="x0">
<bar id="x1">
<bar id="x11">
<bar id="x12">
<div>
<bar id="x13">
<div>
<p/>
</div>
</bar>
</div>
</bar>
</bar>
</bar>
</bars>
---------
I had an embarrassing moment today, when I found that the source of
a severe performance problem was sitting in front of the screen.
Using XSLT 2.0 I am transforming elements and at many points I have
to look up the ancestor axis, but only up to an element with an
attribute "id". Basically I have a deeply nested structure of
topics and I want to analyze ancestors inside the current topic.
The nearest topic is easy to find:
<xsl:variable name="topic" select="ancestor-or-self::*[@id][1]"
as="element()"/>
And then I was doing the following to find all ancestors that share
the same "topic ancestor":
<xsl:variable name="ancestors-in-topic"
select="ancestor-or-self::*[ancestor-or-self::* = $topic]" as="element()*"/>
This did not what I expected and also wasted a lot of resources
because the predicate was true for all or most elements. After some
testing I went with this:
<xsl:variable name="ancestors-in-topic"
select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
generate-id($topic)]" as="element()*"/>
Since that calculation is done very often I am wondering if xsl:key
could be used to speed things up?
Any pointers are very welcome, as always, thanks,
- Michael
PS: My sample XML and XSLT below.
<?xml version="1.0" encoding="UTF-8"?>
<bars id="x0">
<bar id="x1">
<bar id="x11">
<bar id="x12">
<div>
<bar id="x13">
<div>
<p/>
</div>
</bar>
</div>
</bar>
</bar>
</bar>
</bars>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
<xsl:strip-space elements="*"/>
<xsl:template match="p">
<xsl:variable name="topic" select="ancestor-or-self::*[@id][1]"
as="element()"/>
<xsl:variable name="ancestors-in-topic"
select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
generate-id($topic)]" as="element()*"/>
<xsl:copy>
<xsl:attribute name="topic" select="$topic/@id"/>
<xsl:text>Ancestors: </xsl:text>
<xsl:sequence select="$ancestors-in-topic/name()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="* | @*">
<xsl:copy>
<xsl:apply-templates select="@*, node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Expected output for <p>: <p topic="x13">Ancestors: bar div p</p>
--
Syd Bauman, EMT-Paramedic
Senior XML Programmer/Analyst
Northeastern University Women Writers Project
s(_dot_)bauman(_at_)northeastern(_dot_)edu or
Syd_Bauman(_at_)alumni(_dot_)Brown(_dot_)edu
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--