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

for-each over msxsl:node-set, can't xpath outside variable context

265 views
Skip to first unread message

Matthew Sickler

unread,
Jun 24, 2004, 6:54:22 PM6/24/04
to
I'm unsure how to best describe my problem. Essentially i'm trying to
parse over a variable that holds a result-tree fragment, and based on
elements within search for other element of the xml document. The
problem is the Xpath query will only search within the result-tree
fragment.

I've included two examples below, I need example 1 to work. I'm
working in MSXML 4, thanks in advance, matt

<?xml version="1.0"?>
<Navigation>
<Link>
<ParentID>0</ParentID>
<ItemID>1</ItemID>
</Link>
<Link>
<ParentID>0</ParentID>
<ItemID>2</ItemID>
</Link>
<Link>
<ParentID>1</ParentID>
<ItemID>3</ItemID>
</Link>
</Navigation>

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:output method="xml"/>
<xsl:template match="/">

<!-- example 1 -->
<xsl:variable name="test1">
<!-- copy elements with ParentID = 0 into 'test1' variable -->
<xsl:for-each select="//Link[ParentID = 0]">
<xsl:copy>
<xsl:copy-of select="@*|*"/>
</xsl:copy>
</xsl:for-each>
</xsl:variable>

<!-- iterate through list, look for elements with ParentID equal to
current Link -->
<!-- also i'm not sure why i need the /Link -->
<xsl:for-each select="msxsl:node-set($test1)/Link">

<xsl:variable name="id" select="ItemID"/>

<!-- should return 1 when $id = 1, but instead it only looks within
the variable, not the entire document -->
<xsl:value-of select="count(//Link[ParentID = $id])"/>
</xsl:for-each>

<!-- example 2 -->
<xsl:variable name="test2" select="//Link[ParentID = 0]"/>

<!-- this will work -->
<xsl:for-each select="msxsl:node-set($test2)">

<xsl:variable name="id" select="ItemID"/>

<xsl:value-of select="count(//Link[ParentID = $id])"/>
</xsl:for-each>

</xsl:template>
</xsl:stylesheet>

Chris Barber

unread,
Jun 24, 2004, 8:02:38 PM6/24/04
to
Use another variable that holds a reference to the root document and then reference that in your
XPath - that should alleviate any issues with being able to refer to the root document from inside
an RTF.

Your XML:

<?xml version="1.0"?>
<Navigation>
<Link>
<ParentID>0</ParentID>
<ItemID>1</ItemID>
</Link>
<Link>
<ParentID>0</ParentID>
<ItemID>2</ItemID>
</Link>
<Link>
<ParentID>1</ParentID>
<ItemID>3</ItemID>
</Link>
</Navigation>

With This XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"

exclude-result-prefixes="msxsl">
<xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes"/>
<!-- Variable to hold the root document -->
<xsl:variable name="root-document" select="/"/>


<xsl:template match="/">
<!-- example 1 -->
<xsl:variable name="test1">
<!-- copy elements with ParentID = 0 into 'test1' variable -->
<xsl:for-each select="//Link[ParentID = 0]">
<xsl:copy>
<xsl:copy-of select="@*|*"/>
</xsl:copy>
</xsl:for-each>
</xsl:variable>
<!-- iterate through list, look for elements with ParentID
equal to current Link -->
<!-- also i'm not sure why i need the /Link -->

<html>
<head/>
<body>


<xsl:for-each select="msxsl:node-set($test1)/Link">
<xsl:variable name="id" select="ItemID"/>
<!-- should return 1 when $id = 1, but instead it only looks
within the variable, not the entire document -->

<p>Link with ID=<xsl:value-of select="$id"/>
<br/>
Count of links with ParentID of <xsl:value-of select="$id"/> =
<xsl:value-of select="count($root-document//Link[ParentID = $id])"/>
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
<!-- Stop extraneous text output -->
<xsl:template match="text()">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>

Produces:

<html>
<head />
<body>
<p>Link with ID=1
<br />
Count of links with ParentID of 1 = 1
</p>
<p>Link with ID=2
<br />
Count of links with ParentID of 2 = 0
</p>
</body>
</html>

Which might be what you expect?

Chris.

"Matthew Sickler" <sic...@iit.edu> wrote in message
news:fe09cb3e.04062...@posting.google.com...

Matthew Sickler

unread,
Jun 25, 2004, 10:12:09 AM6/25/04
to
thanks, I'll give that a try

would you happen to know the distinction between example 1 and 2, as
far as why it's necessary to set the select query like so
"msxsl:node-set($test1)/Link" for example 1, in order to iterate over
the result set using a for-each

but if you use this, like in example 2


<xsl:variable name="test2" select="//Link[ParentID = 0]"/>

i isn't necessary to include the additional "/Link" like so
"msxsl:node-set($test2)"

they both contain the same result-tree fragment, any help would be
appreciate, i guess i'm just curious

thanks, matt

"Chris Barber" <ch...@blue-canoe.co.uk.NOSPAM> wrote in message news:<OY2F7ekW...@TK2MSFTNGP10.phx.gbl>...

Chris Barber

unread,
Jun 25, 2004, 5:47:34 PM6/25/04
to
Inspecting the variables using Xselerator, the first variable $test1 selection process creates a
document fragment with an implicit '#document-fragment' root node that has to be accommodated for.
The second variable $test2 creates a nodeset directly (the msxsl:node-set() is not required to
iterate it) that contains purely the Link nodes. Your msxsl:node-set() call on the first variable
thus creates the same nodeset but via a temporary document-fragment.

When in doubt get Xselerator out and run the transform in debug mode so you can stop and inspect
what's going on.

0 new messages