Register FAQ Members List Calendar Search Today's Posts Mark Forums Read
 

Go Back   XSL - XML - RSS Forums > XSLForum: Main > XSL-XSD-XML and more

Tags:



Reply
 
LinkBack Thread Tools Display Modes
  #1 (permalink)  
Old 10-21-2008, 10:47 AM
Ebenezer
 
Posts: n/a

Default [XSL] Obtaining an attribute from self or ancestor



Hello!

Let's suppose we have an XML with some nested NODE nodes:

<root attr="first">
<node id="1" attr="mike">
<node id="2" />
<node id="3" attr="dave" />
</node>
<node id="4">
<node id="5" attr="peter" />
</node>
</root>

What I want to achieve is to have an XSL that:
- takes a $id variable externally from a PHP script
- finds the node with @id=$id
- outputs the value "@attr" attribute IF PRESENT, otherwise the parent's
"@attr" attribute IF PRESENT, otherwise the grandparent's... recursively
traversing from parent to parent, until an @attr value is found

This won't work for some nodes:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0">
<xslutput method="html" />
<xsl:template match="root">
<xsl:apply-templates select="//node[@id=$id]" />
</xsl:template>
<xsl:template match="node">
<xsl:choose>
<xsl:when test="not(@attr)"><xsl:apply-templates ".." /></xsl:when>
<xsltherwise><xsl:value-of select="@attr" /></xsltherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Reply With Quote
Sponsored Links
  #2 (permalink)  
Old 10-21-2008, 12:51 PM
Martin Honnen
 
Posts: n/a

Default Re: [XSL] Obtaining an attribute from self or ancestor

Ebenezer wrote:

> What I want to achieve is to have an XSL that:
> - takes a $id variable externally from a PHP script
> - finds the node with @id=$id
> - outputs the value "@attr" attribute IF PRESENT, otherwise the parent's
> "@attr" attribute IF PRESENT, otherwise the grandparent's... recursively
> traversing from parent to parent, until an @attr value is found
>
> This won't work for some nodes:
>
> <?xml version="1.0"?>
> <xsl:stylesheet version="1.0">
> <xslutput method="html" />


You need to define the id parameter
<xslaram name="id"/>

> <xsl:template match="root">
> <xsl:apply-templates select="//node[@id=$id]" />
> </xsl:template>
> <xsl:template match="node">
> <xsl:choose>
> <xsl:when test="not(@attr)"><xsl:apply-templates ".."
> /></xsl:when>


That is not the correct syntax, you need
<xsl:apply-templates select=".."/>
Also it is not clear what you want to do if you do not find a 'node'
ancestor element with an 'attr' attribute.
If you walk up to the 'root element then the template matching that will
lead to infinite recursion. So perhaps you should better use
<xsl:apply-templates select="parent::node"/>
Or if you want to walk up to the 'root' element as well you need a mode e.g.
<xsl:apply-templates select=".." mode="attribute-check"/>

and then you need to add that mode parameter to the template e.g.


<xsl:template match="root">
<xsl:apply-templates select="//node[@id=$id]"
mode="attribute-check" />
</xsl:template>
<xsl:template match="node | root" mode="attribute-check">
<xsl:choose>
<xsl:when test="not(@attr)"><xsl:apply-templates
select="parent::*" /></xsl:when>
<xsltherwise><xsl:value-of select="@attr" /></xsltherwise>
</xsl:choose>
</xsl:template>




--

Martin Honnen
http://JavaScript.FAQTs.com/
Reply With Quote
  #3 (permalink)  
Old 10-21-2008, 12:52 PM
Ebenezer
 
Posts: n/a

Default Re: [XSL] Obtaining an attribute from self or ancestor

Martin Honnen ha scritto:
> Ebenezer wrote:
>
>> What I want to achieve is to have an XSL that:
>> - takes a $id variable externally from a PHP script
>> - finds the node with @id=$id
>> - outputs the value "@attr" attribute IF PRESENT, otherwise the
>> parent's "@attr" attribute IF PRESENT, otherwise the grandparent's...
>> recursively traversing from parent to parent, until an @attr value is
>> found
>>
>> This won't work for some nodes:
>>
>> <?xml version="1.0"?>
>> <xsl:stylesheet version="1.0">
>> <xslutput method="html" />

>
> You need to define the id parameter
> <xslaram name="id"/>


Are you sure? I don't know if it's a standard behaviour, but other
stylesheet's I've made take the parameters with no effort or definition...

> That is not the correct syntax, you need
> <xsl:apply-templates select=".."/>


Sorry, that was my mistake in pasting the code, it's with "select" indeed...

> Also it is not clear what you want to do if you do not find a 'node'
> ancestor element with an 'attr' attribute.
> If you walk up to the 'root element then the template matching that will
> lead to infinite recursion. So perhaps you should better use
> <xsl:apply-templates select="parent::node"/>


Yes! There was an infinite recursion indeed but I didn't find a clue on
it...

> Or if you want to walk up to the 'root' element as well you need a mode
> e.g.
> <xsl:apply-templates select=".." mode="attribute-check"/>
>
> and then you need to add that mode parameter to the template e.g.


This info was really valuable. Thanks a lot and excuse me for the multipost.
Reply With Quote
  #4 (permalink)  
Old 10-21-2008, 03:21 PM
Pavel Lepin
 
Posts: n/a

Default Re: [XSL] Obtaining an attribute from self or ancestor


Ebenezer <vaciapairat@spam.com> wrote in
<bRgLk.86409$Ca.20678@twister2.libero.it>:
> <root attr="first">
> <node id="1" attr="mike">
> <node id="2" />
> <node id="3" attr="dave" />
> </node>
> <node id="4">
> <node id="5" attr="peter" />
> </node>
> </root>
>
> What I want to achieve is to have an XSL that:
> - takes a $id variable externally from a PHP script
> - finds the node with @id=$id
> - outputs the value "@attr" attribute IF PRESENT,
> otherwise the parent's "@attr" attribute IF PRESENT,
> otherwise the grandparent's... recursively traversing from
> parent to parent, until an @attr value is found


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xslaram name="id"/>
<xsl:template match="/">
<xsl:value-of select=
"(//node[@id=$id]/ancestor-or-self::*/@attr)[last()]"
/>
</xsl:template>
</xsl:stylesheet>

HTH, HAND.

--
If we want the average quality of computer programs to rise
by 1000%, all we have to do is carefully to select 90% of
the world's programmers, and shoot them. --Richard
Heathfield in <Sfedncgr46kOPmDanZ2dnUVZ8vCdnZ2d@bt.com>
Reply With Quote
  #5 (permalink)  
Old 10-24-2008, 04:10 AM
Dimitre Novatchev
 
Posts: n/a

Default Re: [XSL] Obtaining an attribute from self or ancestor

Actually, this can be achieved with a single XPath one-liner (even without
XSLT being involved).

Use:

//node[@id = $id]/ancestor-or-self::*[@attr][1]/@attr


Cheers,
Dimitre Novatchev


"Ebenezer" <vaciapairat@spam.com> wrote in message
news:bRgLk.86409$Ca.20678@twister2.libero.it...
> Hello!
>
> Let's suppose we have an XML with some nested NODE nodes:
>
> <root attr="first">
> <node id="1" attr="mike">
> <node id="2" />
> <node id="3" attr="dave" />
> </node>
> <node id="4">
> <node id="5" attr="peter" />
> </node>
> </root>
>
> What I want to achieve is to have an XSL that:
> - takes a $id variable externally from a PHP script
> - finds the node with @id=$id
> - outputs the value "@attr" attribute IF PRESENT, otherwise the parent's
> "@attr" attribute IF PRESENT, otherwise the grandparent's... recursively
> traversing from parent to parent, until an @attr value is found
>
> This won't work for some nodes:
>
> <?xml version="1.0"?>
> <xsl:stylesheet version="1.0">
> <xslutput method="html" />
> <xsl:template match="root">
> <xsl:apply-templates select="//node[@id=$id]" />
> </xsl:template>
> <xsl:template match="node">
> <xsl:choose>
> <xsl:when test="not(@attr)"><xsl:apply-templates ".." /></xsl:when>
> <xsltherwise><xsl:value-of select="@attr" /></xsltherwise>
> </xsl:choose>
> </xsl:template>
> </xsl:stylesheet>



Reply With Quote
  #6 (permalink)  
Old 10-25-2008, 10:13 PM
Dimitre Novatchev
 
Posts: n/a

Default Re: [XSL] Obtaining an attribute from self or ancestor


"Richard Tobin" <richard@cogsci.ed.ac.uk> wrote in message
news:gdsk17$2hbq$1@pc-news.cogsci.ed.ac.uk...
> In article <490139f9$0$17067$6e1ede2f@read.cnntp.org>,
> Dimitre Novatchev <dnovatchev@cnntp.org> wrote:
>
>>Actually, this can be achieved with a single XPath one-liner (even without
>>XSLT being involved).
>>
>>Use:
>>
>> //node[@id = $id]/ancestor-or-self::*[@attr][1]/@attr

>
> Or, if you find it clearer not to repeat @attr:
>
> (//node[@id = $id]/ancestor-or-self::*/@attr)[last()]
>


This may be "clearer" but risks to be less efficient.

Using [1] in a reverse axis is a strong optimization hint and a clever XPath
engine will not traverse the whole way up -- it wil just stop on the first
self-or-ancestor element found that has an "attr" attribute.

Cheers,
Dimitre Novatchev


Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



Contact Us -|- XSL - XML - RSS Forums -|- Archive -|- Top -|-Rules/Disclaimer-|-Help/Support -|-Advertise
© Camley Interactive (camley.info) 2008 - all logos and images are copywrite their respective owners.
Proud member of the Camley Interactive Network
Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.1.0 ©2007, Crawlability, Inc.
All times are GMT. The time now is 01:27 PM.
Style Developed by Epic Designz