This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: A little cross referencing problem
- To: XSL List <xsl-list at lists dot mulberrytech dot com>
- Subject: Re: [xsl] A little cross referencing problem
- From: Joerg Pietschmann <joerg dot pietschmann at zkb dot ch>
- Date: Wed, 22 Aug 2001 17:29:55 +0200
- Organization: ZKB
- Reply-To: xsl-list at lists dot mulberrytech dot com
"Pywell, Andrew" <Andrew.Pywell@compaq.com> 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>
</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>
</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>
</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>
</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