RE: [xsl] Using one nodeset to dictate the format of data from another nodeset

Subject: RE: [xsl] Using one nodeset to dictate the format of data from another nodeset
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Thu, 7 Jun 2007 15:08:41 +0100
You seem to be making this a lot more difficult than it needs to be. It
seems to be a simple join.

(David Carlisle is also making it more difficult, by giving you a lecture
about what node-sets are. He's right of course, but you're not the only one
to misuse the term).

This code:

  <xsl:for-each select="./topic-ref">
     <xsl:apply-templates select="topic-ref"/>
  </xsl:for-each>
  <xsl:apply-templates  select="topic-ref"/>

mirrors exactly the structure of the output you've got, and which you say
you don't want. It's first processing all the grandchildren, then the
children. And when you process the children, it will call itself
recursively, this time processing first the greatgrandchildren, then the
grandchildren. That means the grandchildren will be output twice.

(I can't relate this exactly to your quoted code. Your XML isn't
well-formed, your stylesheet mentions an element "concept" that isn't in
your input, etc.)

For the sample data you've given, all you appear to need is

<xsl:template match="topic-ref">
  <div>
    <xsl:value-of select="key('k', @idref)"/>
    <xsl:apply-templates/>
  </div>
</xsl:template>

<xsl:key name="k" match="content" use="@id"/>

> I would also like to be able to set the header levels within 
> my content based on the depth of the content element. Is it 
> possible to "feed" a template data from the template that called it?

You can either pass parameters to the templates (see xsl:with-param,
xsl:param), or you can determine the current depth using count(ancestor::*).

Michael Kay
http://www.saxonica.com/ 


> 
> I have two nodesets in a single XML document. I am trying to 
> output the data from the first nodeset in a format derived 
> from the contents of the second nodeset. The problem is that 
> the second nodeset is nested elements with the same name. 
> This means I need a recursive template call to make the 
> output nest properly. This results in extra calls to the 
> template. I know what's wrong with my current approach, but I 
> can't figure out how to fix it. Does anyone know how to solve 
> this problems?
> 
> I would also like to be able to set the header levels within 
> my content based on the depth of the content element. Is it 
> possible to "feed" a template data from the template that called it?
> 
> I am using XSL 2.0, Saxon 8B, XML 1.0
> 
> XML:
> <source-data>
>     <content id="id1">content-1</content>
>   <content id="id2">content-2</content>
> </source-data>
> 
> <structure-data>
>   <topic-ref idref="id1" >
>      <topic-ref idref="id2" >
>   </topic-ref>
> </structure-data>
> 
> DESIRED OUTPUT:
> <html>
>    <div>content-1
>      <div>content-2</div>
>   </div>
> </html>
> 
> ACTUAL OUTPUT:
> <html>
>    <div>content-1
>      <div>content-2</div>
>   </div>
>   <div>content-2</div>
> </html>
> 
> 
> XSL:
>   <xsl:key name="id" match="concept" use="@id" />
>   <xsl:key name="idref" match="*" use="@idref" />
> 
>   <xsl:template match="topic-ref">
>     <xsl:choose>
> 
>       <xsl:when test="boolean(./*)">
> 
>         <div class="TOPIC-REF">
> <!-- Select the source node which corresponds to the idref in 
> the structure node -->
>           <xsl:apply-templates select="key('id', ./@idref)"/>
>           <xsl:for-each select="./topic-ref">
>             <xsl:apply-templates select="topic-ref"/>
>           </xsl:for-each>
>           <xsl:apply-templates  select="topic-ref"/>
>         </div>
>       </xsl:when>
>       <xsl:when test="not(./*) and name(../.)='content'">
>         <xsl:apply-templates select="key('id', ./@idref)"/>
>       </xsl:when>
>     </xsl:choose>
>   </xsl:template>
> 
> I have been banging my head against the wall all day and I am 
> hoping there is an elegant way to do this that I just didn't 
> manage to figure out.
> 
> Thank you,
> Rebecca

Current Thread