[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

RE: Specify/determine element's "logical" parent

Subject: RE: Specify/determine element's "logical" parent
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Fri, 24 Sep 2004 00:16:10 +0100
xsl if logical and
... surprised and frustrated at how 
> difficult and complicated it seems for a beginner

I am always frustrated at how long it takes to get to grips with a new
technology, but I am never surprised by it. It's what you should expect; and
the more powerful the technology, the steeper the learning curve is likely
to be.

> I think I need to take a few weeks off and 
> research XSL but I have deliverables. 

The problem is that you're trying to run before you have learned to walk.
There are no short-cuts; learning new skills takes time.
> 
> For instance, I do not understand the difference between the 
> two templates
> listed below, which seem equivalent to me.  The first one 
> fails ("Reference to
> variable or parameter 'parent' must evaluate to a node list") 
> while the second
> works.  Nor do I understand why when both templates are in a single
> stylesheet, only one (the latter?) seems to get applied.  Any help or
> suggestions would be appreciated - hopefully I am doing 
> something really
> stupid and obvious (at least I got rid of xsl:for-each!).

The way you use xsl:variable in the first example, you are creating a new
XML document whose content is a copy of some of the content in your source
document. That new document does not have an id attribute (in fact,
documents never have attributes, only elements have attributes).

What you are trying to do is to set the variable to be a reference to a node
in the source document. In XSLT 2.0 you can do this using the expression:

<xsl:variable name="parent"
   select="if (@parentid) 
           then key( 'ids', @parentid )
           else key( 'ids', ../@id )"/>

It's trickier in XSLT 1.0 because XPath 1.0 doesn't have conditional
expressions: but if you want a variable to be a reference to an existing
node, rather than a newly constructed node containing a copy of the data,
you need to use the "select" attribute.

In this case there's a workaround. The @parentid attribute, if it exists,
will always be after the ../@id attribute in document order. So the
expression 

(../@id | @parentid) [last()]

will select the @parentid attribute if it exists, and the ../@id attribute
otherwise. So you can write:

<xsl:variable name="parent" select="key('ids', (../@id | @parentid)
[last()])"/>

I'm afraid that XSLT coding, especially in 1.0, is full of such tricks, and
there's no way to learn them except by experience.

Michael Kay
http://www.saxonica.com/
 
> 
> <?xml version="1.0" encoding="ISO-8859-1"?>
> <xsl:stylesheet version="1.0" 
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
> <xsl:key name="ids" match="item" use="@id"/>
> 
> <xsl:template match="/">
>   <html>
>     <body>
>       <xsl:apply-templates select="/*//item"/>
>     </body>
>   </html>
> </xsl:template>
> 
> <xsl:template match="item">
>   <xsl:if test="../@id">
>     <xsl:variable name="parent">
>       <xsl:choose>
>         <xsl:when test="@parentid">
> <!-- following line differs -->
>           <xsl:value-of select="key( 'ids', @parentid )" />
>         </xsl:when>
>         <xsl:otherwise>
> <!-- following line differs -->
>           <xsl:value-of select="key( 'ids', ../@id )" />
>         </xsl:otherwise>
>       </xsl:choose>
>     </xsl:variable>
> <!-- following line differs -->
>     <xsl:value-of select="@id" /> is [<xsl:value-of 
> select="$parent/@id" />]<br />
>   </xsl:if>
> </xsl:template>
> 
> <xsl:template match="item">
>   <xsl:if test="../@id">
>     <xsl:variable name="parent">
>       <xsl:choose>
>         <xsl:when test="@parentid">
>           <xsl:value-of select="key( 'ids', @parentid )/@id" />
>         </xsl:when>
>         <xsl:otherwise>
>           <xsl:value-of select="key( 'ids', ../@id )/@id" />
>         </xsl:otherwise>
>       </xsl:choose>
>     </xsl:variable>
>     <xsl:value-of select="@id" /> is [<xsl:value-of 
> select="$parent" />]<br />
>   </xsl:if>
> </xsl:template>
> </xsl:stylesheet>
> 
> <?xml-stylesheet type="text/xsl" href="data.xsl"?>
> <items>
>   <item id="A1">
>     <item id="A2">
>       <item id="A3" />
>     </item>
>   </item>
>   <item id="B1">
>     <item id="B2">
>       <item id="B3" parentid="A2" />
>     </item>
>   </item>
> </items>

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.