[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: Robert Koberg <rob@xxxxxxxxxx>
Date: Thu, 23 Sep 2004 15:39:04 -0700
xsl get date
Hi John,

I think I have written what you need at the bottom, but more comments are inline.

john-xsl-list wrote:

Thanks again for the response. Memory consumption for XML processing in this
environment (something like 4x "file" size) and I'm concerned that creating
these keys every time an XSL is called will be too expensive.



What is the size of the source? I tend to doubt that creating the key would be worse than //


Keys make xsl-life a great deal easier and faster.

I don't mean to gripe and I am sorry to bug the list with this, but I seem to
be headed down a very deep and dark path with XSL. I'm just confusing myself
more the deeper I dig, both surprised and frustrated at how difficult and
complicated it seems for a beginner, and how many of the goals I research
don't seem possible without custom and third-party extensions (dynamic XPath
evaluation, etc.).



You really don't need extensions. Another way to get around extensions is to use the document function. In you can catch the document() call in (for java) an URIResolver and I believe the .NET way is to use an XmlResolver (or something like that). For example:


<xsl:apply-templates select="document('some-dynamic-xml')"/>

or (easier to pass this in as a parameter, but for example)

<xsl:text>Today's date is: </xsl:text>
<xsl:apply-templates select="document('get-date')"/>


and in the resolver you would return the XML source to the transformation (don't know .NET, so psuedo-code):


public Source resolve(String href, String base) {
 if (href.equals("some-dynamic-xml")) {
    return project.buildWhatINeed();
  } else if (href.equals("get-date")) {
    return app.getDate();
 } else {
    return project.getFallback(href);
 }
}


I haven't even approached "how to navigate up my logical
hierarchy". I think I need to take a few weeks off and research XSL but I
have deliverables. I would be happy to RTFM if I could just find the FM
online, and it's so different from my background that I can't even figure out
what to search for.



XSL defintily requires a thought process change. But once you 'get it' you will never want to go back.


The manual is the XSL 1.0 specification:

http://w3.org/TR/xslt

That is probably going to be more difficult to understand than simply getting Mike Kay's book. You don't have to read it cover to cover. It is a reference book with many useful examples.

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.



That is because you are getting the value of the id attribute in the second one. In the first you are getting a nodeset (in this case just one). I am surpised it gives an error, rather than just print nothing. If your item element looked like:


<item id="123">some label</item>

then the value-of would give you 'some label'


Nor do I understand why when both templates are in a single
stylesheet, only one (the latter?) seems to get applied.



Well, you have the same match. You can use the mode attribute to do different things with the same matches.


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!).

<?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">



This choose is not necessary as you already have what you are writing out with value-of. You just want:


<xsl:choose>
       <xsl:when test="@parentid">
         <xsl:value-of select="@parentid" />
       </xsl:when>
       <xsl:otherwise>
         <xsl:value-of select="../@id" />
       </xsl:otherwise>
     </xsl:choose>

Same thing, right?



<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>



I think you have very difficult (bad) XML to work with, but perhaps you want something like:


<xsl:key name="items-with-other-parents" match="item" use="@parentid"/>

<xsl:template match="/">
 <html>
   <body>
     <xsl:apply-templates/>
   </body>
 </html>
</xsl:template>

<>
<xsl:template match="item">
<xsl:variable name="id" select="@id"/>
<!-- check to see if this item has children not nested directly beneath -->
<xsl:variable name="stray-children" select="key('items-with-other-parents', $id<>)"/>


<xsl:choose>
<!-- does it have children directly nested? -->
<xsl:when test="*">
<ul>
<li class="container">
<xsl:value-of select="$id"/>
</li>
<!-- use the $stray-children variable to list all items gathered by the key or //item[@parentid=$id] -->
<xsl:apply-templates select="$stray-children"/>
<><!-- recursively call this template with the directly nested children -->
<xsl:apply-templates/>
<> </ul>
</xsl:when>
<xsl:otherwise>
<li>
<xsl:value-of select="$id"/>
</li>
</xsl:otherwise>
</xsl:choose>
</xsl:template>


<xsl:template match="item" mode="list-children">
  <li>
    <xsl:value-of select="@id"/>
  </li>
</xsl:template>
<>
Does this make sense?

best,
-Rob

<?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.