Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

use preceding or preceding-sibling to access a sorted XML

1,064 views
Skip to first unread message

jin...@yahoo.com

unread,
Jan 21, 2002, 3:23:27 PM1/21/02
to
Suppose I have a xml like this:
<Record>
<AREA>555</AREA>
<NUMBER>1235689</NUMBER>
</Record>
<Record>
<AREA>345</AREA>
<NUMBER>1235689</NUMBER>
</Record>
<Record>
<AREA>555</AREA>
<NUMBER>1232234</NUMBER>
</Record>

What I need to do is to sort this XML first, then for each node,
compare with preceding node to decide how to display.

1. Can anybody tell me what's the difference between preceding and
preceding-sibling?
My experience tell me that preceding::AREA will always return the
AREA from the first node. precding-sibling::node()[1]/AREA returns
the correct value.

2. However, preceding-sibling will only work on the original XML. If
I sort the XML, it will not get the correct node set from the sorted
XML.

3. Then I tried this:
<xsl:variable name="sortedNodes">
<xsl:for-each select="/RECORD">
<xsl:sort select="AREA" order="ascending" data-type="text"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>

<xsl:template match="/">
<xsl:for-each select="$sortedNodes/*">
.............
</xsl:for-each>
</xsl:template>

But I got the error message saying: Reference to variable or parameter
'sortedNodes' must evaluate to a node list.

4. After that, I tried this:
<xsl:for-each select="node-set($sortedNodes)/*">

The error message I got was: 'node-set' is not a valid XSLT or XPath
function.

I would really appreciate that if somebody can point to a right
solution for me. Many thanks in advance.

Jing

Conor Ryan

unread,
Jan 22, 2002, 8:03:21 AM1/22/02
to
Hi Jing,

On 21 Jan 2002 12:23:27 -0800, jin...@yahoo.com wrote:

>Suppose I have a xml like this:
><Record>
> <AREA>555</AREA>
> <NUMBER>1235689</NUMBER>
></Record>
><Record>
> <AREA>345</AREA>
> <NUMBER>1235689</NUMBER>
></Record>
><Record>
> <AREA>555</AREA>
> <NUMBER>1232234</NUMBER>
></Record>
>
>What I need to do is to sort this XML first, then for each node,
>compare with preceding node to decide how to display.
>
>1. Can anybody tell me what's the difference between preceding and
>preceding-sibling?

preceding:: selects all the items specified which precede the context
node, regardless of the level. preceding-sibling:: only selects the
items specified which precede the context node and which are on the
same level as the context node.

> My experience tell me that preceding::AREA will always return the
>AREA from the first node. precding-sibling::node()[1]/AREA returns
>the correct value.

preceding::AREA forms a node-set of all the preceding AREA elements.
if you use xsl:value-of then the first AREA element in this node-set
in document order will be selected.
preceding-sibling::node()[1]/AREA forms a node-set of AREA elements
which are children of the immediate preceding element to the context
node. So to get the correct value you could have used any of the
folowing (assuming Record is the context node):

1. preceding-sibling::node()[1]/AREA
2. preceding-sibling::Record[1]/AREA
3. preceding::Record[1]/AREA
4. preceding::AREA[1]

1 or 2 are preferable to either 3 or 4.

>2. However, preceding-sibling will only work on the original XML. If
>I sort the XML, it will not get the correct node set from the sorted
>XML.
>
>3. Then I tried this:
><xsl:variable name="sortedNodes">
> <xsl:for-each select="/RECORD">
> <xsl:sort select="AREA" order="ascending" data-type="text"/>
> <xsl:copy-of select="."/>
> </xsl:for-each>
></xsl:variable>
>
><xsl:template match="/">
> <xsl:for-each select="$sortedNodes/*">
> .............
> </xsl:for-each>
></xsl:template>
>
>But I got the error message saying: Reference to variable or parameter
>'sortedNodes' must evaluate to a node list.

when you use the content body of a variable the result is a result
tree fragment, not a nodeset. you must use the select attribute on
xsl:variable if you wish to have the variable contain a nodeset.

>4. After that, I tried this:
><xsl:for-each select="node-set($sortedNodes)/*">
>
>The error message I got was: 'node-set' is not a valid XSLT or XPath
>function.

node-set is not a valid XSLT or XPath function but an extension
element offered by several vendors (Saxon, Xalan,...).

>I would really appreciate that if somebody can point to a right
>solution for me. Many thanks in advance.

try the following (i have assumed the xml fragment has a Records root
element node)

<xsl:template match="Records">
<xsl:apply-templates select="Record">


<xsl:sort select="AREA" order="ascending"

data-type="number" />
</xsl:apply-templates>
</xsl:template>

<xsl:template match="Record">
<xsl:if test="preceding-sibling::Record[1]/AREA[.=345]">
<xsl:text>Matched!</xsl:text>
</xsl:if>
</xsl:template>

hope this helps.

rgds,

Conor.
---------
Conor Ryan,
XML Workshop Ltd,
10 Greenmount Industrial Estate, Harolds Cross, Dublin 12, IRELAND.
Email: cr...@xmlw.ie
Phone: +353 1 4547811; Fax: +353 1 4731626
Web: http://www.xmlw.ie/

jin...@yahoo.com

unread,
Jan 23, 2002, 3:50:14 PM1/23/02
to
Thanks, Cornor. That helped!

Jing

0 new messages