Subject: [xsl] Cross-referencing accross multiple documents and sorting: Bug in MSXML4 SP1 when using current() in an xsl:sort/@select value From: David Chryst <dchryst@xxxxxxxxx> Date: Mon, 29 Apr 2002 11:20:46 -0700 (PDT) |
Subject: Cross-referencing accross multiple documents and sorting: Bug in MSXML4 SP1 when using current() in an xsl:sort/@select value Date: 29 Apr, 2002 FYI: There is a bug in MSXML4 when using current() in an xsl:sort/@select value. In that context, current() resolves to the wrong node. Microsoft will release a fix with MSXML 4.0 Serivce Pack 2. No date has been set for that release. Normally, you can use a key() function when doing a cross-reference sort. However, sometimes you have to cross-reference data in 2 separate XML documents and do a sort. For example, suppose you get 1 XML document from some SOAP service that includes month names in the data. You could define the order of months in some static XML document and cross-refence that month-order XML document in your XSLT script using the document() function. In this case, you can't use a key element with the data in the static XML file! Using the current() function: rather than performing 2 separate transforms, I was able to use a single transform, but I had to use the current() function call in the xsl:sort/@select value. This worked great in production for several XSLT scripts when I used MSXML3, but my sort returned data in document order once I upgraded to MSXML4. Here's an example. This example is simpler than what I'm using in production, but it demonstrates the bug: Here's my dynamically-generated XML: Execute the XSLT against this document. <large-collection> <collection name = "groupA"> <ref refid="1"/> <ref refid="3"/> </collection> <collection name = "groupB"> <ref refid="3"/> <ref refid="4"/> </collection> <collection name = "groupC"> <ref refid="1"/> <ref refid="2"/> <ref refid="3"/> <ref refid="4"/> <ref refid="5"/> <ref refid="6"/> <ref refid="7"/> <ref refid="8"/> <ref refid="9"/> </collection> </large-collection> Here's my static XML document that I am cross-referencing. I saved it to c:\temp\parts.xml Do not execute the XSLT against this XML document. This file is cross_refenced in the xsl. If you save this XML as something other than c:\temp\parts.xml, you must alter the XSLT script. <parts> <part id="1" type="type-a" name="name-a"/> <part id="2" type="type-a" name="name-b"/> <part id="3" type="type-b" name="name-c"/> <part id="4" type="type-d" name="name-d"/> <part id="5" type="type-b" name="name-e"/> <part id="6" type="type-c" name="name-f"/> <part id="7" type="type-d" name="name-g"/> <part id="8" type="type-b" name="name-h"/> <part id="9" type="type-c" name="name-i"/> </parts> Here's my XSLT that takes the parts referenced in groupC of the dynamically-generated XML, and sorts all the parts in that group by type, then by name: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" /> <xsl:variable name="MyGroup">groupC</xsl:variable><!--normally this would be a param--> <xsl:variable name="MyParts" select="document('c:\temp\parts.xml')/parts"/> <xsl:template match="/large-collection"> <xsl:apply-templates select="collection[@name = $MyGroup]" /> </xsl:template> <xsl:template match="/large-collection/collection"> <xsl:for-each select="ref"> <xsl:sort select="$MyParts/part[@id = (current())/@refid]/@type" order="ascending"/> <xsl:sort select="$MyParts/part[@id = (current())/@refid]/@name" order="ascending"/> type: <xsl:value-of select="concat($MyParts/part[@id = (current())/@refid]/@type, ' name: ', $MyParts/part[@id = (current())/@refid]/@name, ' id: ', $MyParts/part[@id = (current())/@refid]/@id)"/> </xsl:for-each> </xsl:template> </xsl:stylesheet> Here's the output I get when I execute the XSLT using MSXML3 DOM and processor: type: type-a name: name-a id: 1 type: type-a name: name-b id: 2 type: type-b name: name-c id: 3 type: type-b name: name-e id: 5 type: type-b name: name-h id: 8 type: type-c name: name-f id: 6 type: type-c name: name-i id: 9 type: type-d name: name-d id: 4 type: type-d name: name-g id: 7 Here's the output I get when I execute the same XSLT using MSXML4 DOM and processor: type: type-a name: name-a id: 1 type: type-a name: name-b id: 2 type: type-b name: name-c id: 3 type: type-d name: name-d id: 4 type: type-b name: name-e id: 5 type: type-c name: name-f id: 6 type: type-d name: name-g id: 7 type: type-b name: name-h id: 8 type: type-c name: name-i id: 9 Possible workarounds: 1) Normally, one can avoid using the current function call by simply using a key. That is not possible in this case because XSLT does not allow you to form a key from an outside document XML tree. 2) You could duplicate the data kept in c:\temp\parts.xml in every dynamically-generated XML document (by modifying the SOAP service that generates the XML or by running an extra transform) but that seems a little in-elegant! 3) You can revert back to MSXML3 or some other XSLT processor that allows use of current() in an xsl:sort/@select value. 4) You can wait for MSXML4 SP2 David Chryst __________________________________________________ Do You Yahoo!? Yahoo! Health - your guide to health and wellness http://health.yahoo.com XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] Re: Re: Re: Create a node set, Dimitre Novatchev | Thread | [xsl] Recursion Help with Summing D, Seth Ladd |
[xsl] Re: Re: Re: Create a node set, Dimitre Novatchev | Date | Re: [xsl] problem in using * as a d, Oleg Tkachenko |
Month |