Subject: [xsl] key() in match pattern of xsl:key From: "Joel E. Denny" <jdenny@xxxxxxxxxxxxxxx> Date: Fri, 9 Dec 2005 16:24:08 -0500 (EST) |
Should it be possible to reference one key in the match pattern of another? I did not find this usage discussed in the XSLT 1.0 recommendation or elsewhere on the web. Did I miss it? I haven't quite deciphered the XSLT 2.0 recommendation well enough yet. Does it address this usage? Even if this usage is non-standard, is it widely supported? Moreover, is there typically any restriction on the declaration order of keys? That is, among the keys, is it `declaration before use' or `use before declaration'? Or either way? If this is a well understood issue, then the rest of this email is probably irrelevant. In case it is not, I provide more explanation (with examples) for this usage and explain what I know so far. Maybe there's a more standard way to accomplish what I want? Or maybe XSLT 2.0 offers another approach without sacrificing efficiency? I find that this technique makes computing set differences (and surely there are other applications) readable, efficient, and scalable. For example, given: <xsl:key name="keyB" match="B" use="." /> The variable AnotB stores the final set I'm after: <xsl:variable name="AnotB" select="//A[ not( key( 'keyB', . ) ) ]" /> However, there are times when I may want a key defined for that set for the sake of efficiency: <xsl:key name="keyAnotB" match="A[ not( key( 'keyB', . ) ) ]" use = "." /> Moreover, as my project grows, I may find that I need to use keyAnotB in the computation of yet another set. I have tested this computation with libxslt 1.1.15. Although Daniel Veillard has informed me that this usage is currently outside the realm of specified functionality, the above does work for my simple test cases. I mention this only because it may offer some clue as to whether it's possible to implement this and implement it efficiently. Note that libxslt builds the keys in the reverse order of the declarations, so it's `use before declaration'. That is, keyAnotB must be declared before keyB. If you would like to see a working test case, find the XML and XSLT at the end of this email. The desired output is: <?xml version="1.0"?> $A: 1.0: A=1, B=1, AnotB=0 2.0: A=1, B=0, AnotB=1 3.0: A=1, B=0, AnotB=1 $B: 1.0: A=1, B=1, AnotB=0 4.0: A=0, B=1, AnotB=0 5.0: A=0, B=1, AnotB=0 $AnotB: 2.0: A=1, B=0, AnotB=1 3.0: A=1, B=0, AnotB=1 I have also been told by Kasimier Buchcik that this test case works fine in Stylus Studio regardless of the declaration order. With regard to efficiency, it is interesting to note that I also tried an alternative approach with EXSLT's user defined functions. For example, I I converted keyB to a function and called it from keyAnotB. This also works under libxslt 1.1.15. However, for a much more complex test case than the one below, I noticed a jump from 1sec to 25sec processing time. This seems reasonable since the function must iterate the document on every call but the key need not. Thanks. Joel --------------------------------------------------------- <?xml version="1.0" encoding="iso-8859-1"?> <test> <A>1.0</A> <A>2.0</A> <A>3.0</A> <B>1.0</B> <B>4.0</B> <B>5.0</B> </test> --------------------------------------------------------- <?xml version="1.0" encoding="iso-8859-1"?> <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <xsl:key name="keyA" match="A" use="." /> <xsl:key name="keyAnotB" match="A[ not( key( 'keyB', . ) ) ]" use = "." /> <xsl:key name="keyB" match="B" use="." /> <xsl:variable name="AnotB" select="//A[ not( key( 'keyB', . ) ) ]" /> <xsl:template match="/"> <xsl:text>$A: </xsl:text> <xsl:for-each select="//A"> <xsl:text> </xsl:text><xsl:value-of select="." /> <xsl:text>: A=</xsl:text> <xsl:value-of select="count( key( 'keyA', . ) )" /> <xsl:text>, B=</xsl:text> <xsl:value-of select="count( key( 'keyB', . ) )" /> <xsl:text>, AnotB=</xsl:text> <xsl:value-of select="count( key( 'keyAnotB', . ) )" /> <xsl:text> </xsl:text> </xsl:for-each> <xsl:text>$B: </xsl:text> <xsl:for-each select="//B"> <xsl:text> </xsl:text><xsl:value-of select="." /> <xsl:text>: A=</xsl:text> <xsl:value-of select="count( key( 'keyA', . ) )" /> <xsl:text>, B=</xsl:text> <xsl:value-of select="count( key( 'keyB', . ) )" /> <xsl:text>, AnotB=</xsl:text> <xsl:value-of select="count( key( 'keyAnotB', . ) )" /> <xsl:text> </xsl:text> </xsl:for-each> <xsl:text>$AnotB: </xsl:text> <xsl:for-each select="$AnotB"> <xsl:text> </xsl:text><xsl:value-of select="." /> <xsl:text>: A=</xsl:text> <xsl:value-of select="count( key( 'keyA', . ) )" /> <xsl:text>, B=</xsl:text> <xsl:value-of select="count( key( 'keyB', . ) )" /> <xsl:text>, AnotB=</xsl:text> <xsl:value-of select="count( key( 'keyAnotB', . ) )" /> <xsl:text> </xsl:text> </xsl:for-each> </xsl:template> </xsl:transform> ---------------------------------------------------------
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] Re: Default namespace in , David Carlisle | Thread | RE: [xsl] key() in match pattern of, Michael Kay |
[xsl] Re: Default namespace in resu, Phil Endecott | Date | RE: [xsl] Preserving whitespace bet, Haarman, Michael |
Month |