Re: [xsl] XPath problem with getting all ancestors

Subject: Re: [xsl] XPath problem with getting all ancestors
From: Vyacheslav Sedov <vyacheslav.sedov@xxxxxxxxx>
Date: Fri, 23 Oct 2009 16:07:04 +0400
it is ok - you copy whole node - not reference so this stats refer to
new constructed node

On Fri, Oct 23, 2009 at 4:03 PM, Jostein Austvik Jacobsen
<josteinaj@xxxxxxxxx> wrote:
> Ok, I've stripped it down a fair bit. When I run this:
>
>
> <?xml version="1.0" encoding="utf-8"?>
> <document>
>       <article>
>               <meta>
>                       <title>Title</title>
>               </meta>
>               <content>
>                       <para>
>                               <note id="1">text</note>
>                       </para>
>               </content>
>       </article>
> </document>
>
>
> through this:
>
>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
> version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema";
> xmlns:mf="http://example.com/2009/mf"; exclude-result-prefixes="xs mf">
>
>        <xsl:template match="document">
>                <document>
>                        <meta/>
>                        <content>
>                                <xsl:for-each select="article">
>                                        <xsl:sort select="(.//@page)[1]"/>
>                                        <xsl:apply-templates
select="article"/>
>                                </xsl:for-each>
>                                <xsl:apply-templates/>
>                        </content>
>                </document>
>        </xsl:template>
>
>        <xsl:template match="article">
>                <xsl:variable name="v1">
>                        <xsl:copy-of select="content/node()"/>
>                </xsl:variable>
>                <xsl:sequence select="mf:group($v1/node())"/>
>        </xsl:template>
>        <xsl:function name="mf:group" as="node()*">
>                <xsl:param name="nodes" as="node()*"/>
>                <xsl:for-each-group select="$nodes"
group-starting-with="foo">
>                        <xsl:apply-templates/>
>                </xsl:for-each-group>
>        </xsl:function>
>
>        <xsl:template match="note">
>                The note at /article/content/para/note reads:
>                ancestors="<xsl:value-of select="count(ancestor::*)"/>"
>                preceding="<xsl:value-of select="count(preceding::*)"/>"
>                contentNum="<xsl:value-of
select="count(preceding::content)"/>"
>                numberTest="<xsl:number level="any" count="content"/>"
>        </xsl:template>
>
> </xsl:stylesheet>
>
>
> I get this:
>
>
> <?xml version="1.0" encoding="UTF-8"?>
> <document>
>        <meta/>
>        <content>
>                The note at /article/content/para/note reads:
>                ancestors="1"
>                preceding="0"
>                contentNum="0"
>                numberTest=""
>        </content>
> </document>
>
>
> In this case I would expect:
> ancestors="3" (para,content,article)
> preceding="2" (meta,title)
>
> But I guess I'm applying the template in a wrong way?
>
> Regards
> Jostein
>
> 2009/10/23 Jostein Austvik Jacobsen <josteinaj@xxxxxxxxx>:
>> David/Syd: I tried replacing the value-of with <xsl:number level="any"
>> count="content"/>, but it returned nothing. I'm sure I'm using it
>> wrong though so I'll have myself a read on xsl:number.
>> Syd: Sorry about the misplaced match. I tried it myself now and
>> actually got the same as you.
>> Syd/Michael: I'll try to strip down my stylesheet to localize the
>> problem further, then I'll post it back here.
>>
>> Thanks
>> Jostein
>>
>> 2009/10/23 Michael Kay <mike@xxxxxxxxxxxx>:
>>>
>>> My guess (and it's a completely wild one) is that you aren't applying
>>> templates to the note element in the source tree as you have shown it,
but
>>> to a copy of the note element in some smaller tree, probably a tree
rooted
>>> at the para element.
>>>
>>> To confirm that we would need to see more of the stylesheet. Or, within
the
>>> match="note" template, do
>>>
>>> <xsl:message><xsl:copy-of select="/"/></xsl:message>
>>>
>>> to see what tree you are processing at the time.
>>>
>>> Regards,
>>>
>>> Michael Kay
>>> http://www.saxonica.com/
>>> http://twitter.com/michaelhkay
>>>
>>>> -----Original Message-----
>>>> From: Jostein Austvik Jacobsen [mailto:josteinaj@xxxxxxxxx]
>>>> Sent: 23 October 2009 11:27
>>>> To: xsl-list
>>>> Subject: [xsl] XPath problem with getting all ancestors
>>>>
>>>> I've got a document like this:
>>>>
>>>> <?xml version="1.0" encoding="utf-8"?>
>>>> <document>
>>>>       <article>
>>>>               <meta>
>>>>                       <title>Title</title>
>>>>               </meta>
>>>>               <content>
>>>>                       <headline>Headline</headline>
>>>>                       <para>
>>>>                               <note id="1">text</note>
>>>>                       </para>
>>>>               </content>
>>>>       </article>
>>>> </document>
>>>>
>>>> And in a template for the note tags I'm trying to use the
>>>> ancestor axis to get the list [ para , content , article ].
>>>> However, I only seem to get [ para ] with ancestor::* and [ para , ""
>>>> ] with ancestor::node().
>>>> When I test it like this:
>>>>
>>>> <xsl:template match="note">
>>>>               ancestors="<xsl:value-of select="count(ancestor::*)"/>"
>>>>               preceding="<xsl:value-of select="count(preceding::*)"/>"
>>>>               contentNum="<xsl:value-of
>>>> select="count(preceding::content)"/>"
>>>> </xsl:template match>
>>>>
>>>> ...I get ancestors="1", preceding="2" and contentNum="0" as output.
>>>>
>>>> What I actually need to do is to count the number of content
>>>> nodes preceding the current note (relevant for the input XML
>>>> note numbering scheme). I did so earlier in the document (for
>>>> referencing the actual
>>>> notes) when matching document like this:
>>>>
>>>> <xsl:template match="document">
>>>>       (...)
>>>>       <xsl:for-each select="//note">
>>>>               <note>
>>>>                       <xsl:attribute name="id"><xsl:value-of
>>>> select="count(ancestor::content/preceding::content)"/></xsl:attribute>
>>>>                       <p><xsl:apply-templates/></p>
>>>>               </note>
>>>>       </xsl:for-each>
>>>>       (...)
>>>> </xsl:template>
>>>>
>>>> So here I get access to all of the notes ancestors. In
>>>> retrospect I could probably have used
>>>> select="count(preceding::content)" instead, but still...
>>>>
>>>> How come that I cannot access the notes ancestors from my
>>>> note template?
>>>>
>>>> Regards
>>>> Jostein

Current Thread