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

Re: A little cross referencing problem

Subject: Re: A little cross referencing problem
From: Joerg Pietschmann <joerg.pietschmann@xxxxxx>
Date: Wed, 22 Aug 2001 17:29:55 +0200
iso cross referencing
"Pywell, Andrew" <Andrew.Pywell@xxxxxxxxxx> wrote:
> I have a little cross-referencing problem. My XML looks like this
> 
> <?xml version="1.0"?>
> <messageData>
>  <message dir="0" key="234" text="bla bla"/>
>  <message dir="1" key="235" text="more bla bla"/>
[snip]
>  <in key="240" status="File Error"/>
>  <in key="241" status="No Error"/>
>  <out key="235" status="No Error"/>
>  <out key="237" status="No Error"/>
> </messageData>
[snip]
> 
> If dir="0" then I need to find the matching "key" in <in> and extract the
> value of "status". Similarly if dir="1" the I need the "status" of the
> matching <out> record
> 
There are several solutions. One is to use xsl:choose to discriminate
whether the direction ist "In" or "Out":

  <?xml version="1.0"?>
  <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" encoding="ISO-8859-1"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="message">
      <xsl:choose>
        <xsl:when test="@dir=0">
          <xsl:text>In </xsl:text>
          <xsl:value-of select="/*/in[@key=current()/@key]/@status"/>
        </xsl:when>
        <xsl:when test="@dir=1">
          <xsl:text>Out </xsl:text>
          <xsl:value-of select="/*/out[@key=current()/@key]/@status"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:message terminate="yes">Error in data</xsl:message>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text> </xsl:text>
      <xsl:value-of select="@text"/>
      <xsl:text>&#xD;&#xA;</xsl:text>
    </xsl:template>
  </xsl:stylesheet>

Not that the code above will complain if the key attribute of a
message is illegal, but will not notice if there are no or more
than one matching in/out elements.

You can have more fun with keys, and perhaps some performance
gain:

  <?xml version="1.0"?>
  <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" encoding="ISO-8859-1"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="in" match="in" use="@key"/>
    <xsl:key name="out" match="out" use="@key"/>

    <xsl:template match="message">
      <xsl:choose>
        <xsl:when test="@dir=0">
          <xsl:text>In </xsl:text>
          <xsl:value-of select="key('in',@key)/@status"/>
        </xsl:when>
        <xsl:when test="@dir=1">
          <xsl:text>Out </xsl:text>
          <xsl:value-of select="key('out',@key)/@status"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:message terminate="yes">Error in data</xsl:message>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text> </xsl:text>
      <xsl:value-of select="@text"/>
      <xsl:text>&#xD;&#xA;</xsl:text>
    </xsl:template>
  </xsl:stylesheet>

Now for even more fun and some obfuscation, you can select the
key dynamically

  <?xml version="1.0"?>
  <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" encoding="ISO-8859-1"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="k0" match="in" use="@key"/>
    <xsl:key name="k1" match="out" use="@key"/>

    <xsl:template match="message">
      <xsl:apply-templates select="key(concat('k',@dir),@key)"/>
      <xsl:text> </xsl:text>
      <xsl:value-of select="@text"/>
      <xsl:text>&#xD;&#xA;</xsl:text>
    </xsl:template>

    <xsl:template match="in">
      <xsl:text>In </xsl:text>
      <xsl:value-of select="@status"/>
    </xsl:template>
    <xsl:template match="out">
      <xsl:text>Out </xsl:text>
      <xsl:value-of select="@status"/>
    </xsl:template>
    <xsl:template match="/">
      <xsl:apply-templates select="*/message"/>
    </xsl:template>
  </xsl:stylesheet>

Think about why there is suddenly a template matching "/" necessary.

The code above will get a nasty runtime error if a dir attribute contains
an illegal value. This leads to my favorite piece of code which guards
the invocation of the dynamically selected key by having a key lookup in
the stylesheet whether the key actually exists.

    <xsl:key name="key" match="xsl:key" use="@name"/>
    <xsl:template match="message">
      <xsl:variable name="key" select="concat('k',@dir)"/>
      <xsl:choose>
        <xsl:when test="document('')[key('key',$key)]">
          <xsl:apply-templates select="key($key,@key)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:message terminate="yes">Error in data</xsl:message>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text> </xsl:text>
      <xsl:value-of select="@text"/>
      <xsl:text>&#xD;&#xA;</xsl:text>
    </xsl:template>

I hope you didn't get an overdose of keys by now :-)

Have fun!
J.Pietschmann

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


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.