You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@xalan.apache.org by Sean <ja...@wideasleep.com> on 2001/03/07 23:13:44 UTC

XPath Question

I am trying to do the following, I want to select the deepest ancestor or
the node itself that has a defined <desc> that has a child who's has a
certain @id.  Here is an example dataset:

<xnav>
<item id="1">
    <desc>test 1</desc>
    <item id="1.1">
        <something>test</something>
    </item>
    <item id="1.2">
        <desc>test 1.2</desc>
    </item>
</item>
<item id="2">
    <desc>test 2</desc>
    <item id="2.1">
        <desc>test 2.1</desc>
        <item id="2.1.1">
           <something>test 2.1.1</something>
        </item>
    </item>
</item>
</xnav>

So if say the id was "1.1" I actually want the description of the first item
node since 1.1 does not have a defined <desc> but if the id I was looking
for was 1.2 it would return the <desc> for 1.2 since that one is set.

So here is what I have so far:

    <xsl:value-of select="xnav/child::item[ descendant-or-self::item[@id =
/webpage/@id] and string-length(desc) != 0]/desc"/>

This always seems to return the <desc> for id=1 instead of the1.2.  Anyone
have any idea on what I am doing wrong?  Any suggestions?

Thanks,
Sean

Re: XPath Question

Posted by Gary L Peskin <ga...@firstech.com>.
Sean wrote:
> 
> I am trying to do the following, I want to select the deepest ancestor or
> the node itself that has a defined <desc> that has a child who's has a
> certain @id.  Here is an example dataset:
> 
> <xnav>
> <item id="1">
>     <desc>test 1</desc>
>     <item id="1.1">
>         <something>test</something>
>     </item>
>     <item id="1.2">
>         <desc>test 1.2</desc>
>     </item>
> </item>
> <item id="2">
>     <desc>test 2</desc>
>     <item id="2.1">
>         <desc>test 2.1</desc>
>         <item id="2.1.1">
>            <something>test 2.1.1</something>
>         </item>
>     </item>
> </item>
> </xnav>
> 
> So if say the id was "1.1" I actually want the description of the first item
> node since 1.1 does not have a defined <desc> but if the id I was looking
> for was 1.2 it would return the <desc> for 1.2 since that one is set.
> 
> So here is what I have so far:
> 
>     <xsl:value-of select="xnav/child::item[ descendant-or-self::item[@id =
> /webpage/@id] and string-length(desc) != 0]/desc"/>
> 
> This always seems to return the <desc> for id=1 instead of the1.2.  Anyone
> have any idea on what I am doing wrong?  Any suggestions?
> 
> Thanks,
> Sean

Sean --

You're close.  This will work assuming you retain your "id" numbering
scheme as shown in the examples.

First, you'll only get those items which are children of xnav.  What you
want are any descendants of xnav that match the criteria so add an extra
/ after the existing one in xname/child.

Next, xsl:value-of will convert the select expression to a string as if
by a call to the string() function.  In this case, if /webpage/@id is
1.2, your select expression will consist of a node-set of two desc
nodes, one with a child of "test 1" and one with a child of "test 1.2". 
When passing a node-set to the string() function, it returns the string
value of the FIRST node in the node-set, or "test 1".

You can see that there are two nodes in the node-set by changing
xsl:value-of to xsl:copy-of.

Because of the way your input XML is structured, you want the node in
the node-set that is the last in document order so add a "position() =
last()" condition in your predicate.

The expression you want is, therefore:

<xsl:value-of select="xnav//child::item[descendant-or-self::item[@id =
 /webpage/@id] and string-length(desc) != 0]/desc and position() =
last()" />

BTW, you'll usually get better answers to these straight XSLT questions
on XSL-List.

Gary