Specify an element in a nodeset directly

E

eric.goforth

Hello,

Is there any way to directly access an element in a nodeset?

For example, if working with:

<blahs rec_count="16">
<blah>
<yada>abc</yada>
</blah>
<blah>
<yada>123</yada>
</blah>
<blah>
<yada>xyz</yada>
</blah>
</blahs>

For instance, I could specify something like blahs/blah[2]/yada and get
the value of "123"?

-Eric
 
P

Peter Flynn

Hello,

Is there any way to directly access an element in a nodeset?

For example, if working with:

<blahs rec_count="16">
<blah>
<yada>abc</yada>
</blah>
<blah>
<yada>123</yada>
</blah>
<blah>
<yada>xyz</yada>
</blah>
</blahs>

For instance, I could specify something like blahs/blah[2]/yada and get
the value of "123"?

Yes, exactly that. In XSLT, for example, you would write

<xsl:value-of select="blahs/blah[2]/yada"/>

But this doesn't have anything to do with nodesets.
It's just an XPath statement referencing an element.

///Peter
 
E

eric.goforth

Peter said:
Hello,

Is there any way to directly access an element in a nodeset?

For example, if working with:

<blahs rec_count="16">
<blah>
<yada>abc</yada>
</blah>
<blah>
<yada>123</yada>
</blah>
<blah>
<yada>xyz</yada>
</blah>
</blahs>

For instance, I could specify something like blahs/blah[2]/yada and get
the value of "123"?

Yes, exactly that. In XSLT, for example, you would write

<xsl:value-of select="blahs/blah[2]/yada"/>

But this doesn't have anything to do with nodesets.
It's just an XPath statement referencing an element.

Peter,

Hmmm, well the situation in a little more detail is that I'm passing in
this nodeset, I believe that's the right word, in a parameter.

So my entire XML document looks more like:

<mydoc>
<mystuff>
<blahs rec_count="3">
<blah>
<yada>abc</yada>
</blah>
<blah>
<yada>123</yada>
</blah>
<blah>
<yada>xyz</yada>
</blah>
</blahs>
</mystuff>
</mydoc>

I'm passing the blahs to a template as a parameter like so:


<xsl:apply-templates select="somestuff">
<xsl:with-param name="myblahs"
select="/mydoc/mystuff/blahs"></xsl:with-param>
</xsl:apply-templates>


Then in my template it looks something like:

<xsl:template match="somestuff">

<xsl:param name="myblahs"/>

.... Do some stuff...

</xsl:template >

So debugging the transformation of the somestuff template in XML Spy,
if I look at $myblahs in the XPath-Watch, I see NodeSet[1]. If I click
on the NodeSet[1] beside the $myblahs in the XPath-Watch I see blahs
with a rec_count="3", so my data made it inside the somestuff template.

However, if I do a <xsl:value-of select="$myblahs/blah[2]/yada"/>

I get an Error: Invalid XPath.

Thanks,
Eric
 
D

Dimitre Novatchev

However, if I do a <xsl:value-of select="$myblahs/blah[2]/yada"/>

Try:

$myblahs[2]/yada


Cheers,
Dimitre Novatchev

Peter said:
Hello,

Is there any way to directly access an element in a nodeset?

For example, if working with:

<blahs rec_count="16">
<blah>
<yada>abc</yada>
</blah>
<blah>
<yada>123</yada>
</blah>
<blah>
<yada>xyz</yada>
</blah>
</blahs>

For instance, I could specify something like blahs/blah[2]/yada and get
the value of "123"?

Yes, exactly that. In XSLT, for example, you would write

<xsl:value-of select="blahs/blah[2]/yada"/>

But this doesn't have anything to do with nodesets.
It's just an XPath statement referencing an element.

Peter,

Hmmm, well the situation in a little more detail is that I'm passing in
this nodeset, I believe that's the right word, in a parameter.

So my entire XML document looks more like:

<mydoc>
<mystuff>
<blahs rec_count="3">
<blah>
<yada>abc</yada>
</blah>
<blah>
<yada>123</yada>
</blah>
<blah>
<yada>xyz</yada>
</blah>
</blahs>
</mystuff>
</mydoc>

I'm passing the blahs to a template as a parameter like so:


<xsl:apply-templates select="somestuff">
<xsl:with-param name="myblahs"
select="/mydoc/mystuff/blahs"></xsl:with-param>
</xsl:apply-templates>


Then in my template it looks something like:

<xsl:template match="somestuff">

<xsl:param name="myblahs"/>

... Do some stuff...

</xsl:template >

So debugging the transformation of the somestuff template in XML Spy,
if I look at $myblahs in the XPath-Watch, I see NodeSet[1]. If I click
on the NodeSet[1] beside the $myblahs in the XPath-Watch I see blahs
with a rec_count="3", so my data made it inside the somestuff template.

However, if I do a <xsl:value-of select="$myblahs/blah[2]/yada"/>

I get an Error: Invalid XPath.

Thanks,
Eric
 
E

eric.goforth

Dimitre said:
However, if I do a <xsl:value-of select="$myblahs/blah[2]/yada"/>

Try:

$myblahs[2]/yada


Cheers,
Dimitre Novatchev

Peter said:
(e-mail address removed) wrote:
Hello,

Is there any way to directly access an element in a nodeset?

For example, if working with:

<blahs rec_count="16">
<blah>
<yada>abc</yada>
</blah>
<blah>
<yada>123</yada>
</blah>
<blah>
<yada>xyz</yada>
</blah>
</blahs>

For instance, I could specify something like blahs/blah[2]/yada and get
the value of "123"?

Yes, exactly that. In XSLT, for example, you would write

<xsl:value-of select="blahs/blah[2]/yada"/>

But this doesn't have anything to do with nodesets.
It's just an XPath statement referencing an element.

Peter,

Hmmm, well the situation in a little more detail is that I'm passing in
this nodeset, I believe that's the right word, in a parameter.

So my entire XML document looks more like:

<mydoc>
<mystuff>
<blahs rec_count="3">
<blah>
<yada>abc</yada>
</blah>
<blah>
<yada>123</yada>
</blah>
<blah>
<yada>xyz</yada>
</blah>
</blahs>
</mystuff>
</mydoc>

I'm passing the blahs to a template as a parameter like so:


<xsl:apply-templates select="somestuff">
<xsl:with-param name="myblahs"
select="/mydoc/mystuff/blahs"></xsl:with-param>
</xsl:apply-templates>


Then in my template it looks something like:

<xsl:template match="somestuff">

<xsl:param name="myblahs"/>

... Do some stuff...

</xsl:template >

So debugging the transformation of the somestuff template in XML Spy,
if I look at $myblahs in the XPath-Watch, I see NodeSet[1]. If I click
on the NodeSet[1] beside the $myblahs in the XPath-Watch I see blahs
with a rec_count="3", so my data made it inside the somestuff template.

However, if I do a <xsl:value-of select="$myblahs/blah[2]/yada"/>

I get an Error: Invalid XPath.

Thanks,
Eric

I've figured out how to do get it to work. <xsl:value-of
select="$myblahs/blah[2]/yada"/> is working for me now, I think that I
must have had a type in there.

The only problem I'm having now is figuring out how to make the "2"
variable.

For instance:

<xsl:value-of
select="$myblahs/blah[/xpath1/xpath2/someintegervalue]/yada"/>

-Eric
 
E

eric.goforth

Martin said:
<xsl:value-of
select="$myblahs/blah[/xpath1/xpath2/someintegervalue]/yada"/>

$myblahs/blah[/xpath1/xpath2/someintegervalue = position()]/yada

Martin,

Hmmm, that's not working for me. If I put in a "1" or a "2" it works,
but not with the "variable".

In my case

<xsl:apply-templates select="thingsummary">
<xsl:with-param name="furballs"
select="/xpath1/xpath2/furballssummary"></xsl:with-param>
</xsl:apply-templates>

</xsl:template>

<xsl:template match="thingsummary">

<xsl:param name="furballs"/>

<xsl:apply-templates select="thing[(position() mod 2)=1]">
<xsl:with-param name="furballs"
select="$furballs"></xsl:with-param>
</xsl:apply-templates>

</xsl:template>

<xsl:template match="thing[(position() mod 2)=1]">

<xsl:param name="furballs"/>

<!-- This works-->
<xsl:value-of select="thingintegerfield1"/>

<!-- This works-->
<xsl:value-of select="$furballs/furball[1]/furballmember"/>

<!-- This works-->
<xsl:value-of select="$furballs/furball[1=
position()]/furballmember"/>

<!-- This does not work-->
<xsl:value-of
select="$furballs/furball[1=thingintegerfield1]/furballmember"/>

</xsl:template>

Thanks
Eric
 
R

roy axenov

Martin said:
<xsl:value-of select="
$myblahs/blah[/xpath1/xpath2/someintegervalue]/yada
"/>

$myblahs/blah
[/xpath1/xpath2/someintegervalue=position()]/yada

Hmmm, that's not working for me. If I put in a "1" or a
"2" it works, but not with the "variable".

Your example is awfully vague. For better results, provide
a sample XML and a minimum XSLT demonstrating your problem.
<xsl:template match="thing[(position() mod 2)=1]">
<xsl:param name="furballs"/>
<!-- This works-->
<xsl:value-of select="thingintegerfield1"/>
<!-- This does not work-->
<xsl:value-of select="
$furballs/furball[1=thingintegerfield1]/furballmember
"/>
</xsl:template>

First of all, the [1=thingintegerfield1] predicate should
be [position()=thingintegerfield1] if I understood
correctly what you're trying to do (it's hard to be sure
without a working example).

Even then, I'd say you don't understand how contexts work.
Let's assume this template matched the node
/foo[1]/bar[1]/thing[1]. What does thingintegerfield1 in
the XPath marked as 'This works' refer to then? The answer
is '/foo[1]/bar[1]/thing[1]/thingintegerfield1'. And what
does thingintegerfield1 in the XPath marked as 'This does
not work' refer to? '$furballs/furball/thingintegerfield1'.
What you probably need is current()/thingintegerfield1,
although, once again, it's hard to be sure without a
working example.

To demonstrate:

XML:

<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar>
<xyzzy>
<int>3</int>
</xyzzy>
</bar>
<nodeset>
<node>
<str>wrong (1)</str>
<int>3</int>
</node>
<node>
<str>wrong (2)</str>
<int>2</int>
</node>
<node>
<str>right (3)</str>
<int>1</int>
</node>
</nodeset>
</foo>

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:eek:utput method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="descendant::xyzzy">
<xsl:with-param name="ns" select="/foo/nodeset"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="/foo/bar/xyzzy">
<xsl:param name="ns"/>
My Int: <xsl:value-of select="int"/>
Wrong: <xsl:value-of select="
$ns/node[int=position()]/str"/>
Right: <xsl:value-of select="
$ns/node[current()/int=position()]/str"/>
</xsl:template>
</xsl:stylesheet>
 
E

eric.goforth

roy said:
Martin said:
(e-mail address removed) wrote:
<xsl:value-of select="
$myblahs/blah[/xpath1/xpath2/someintegervalue]/yada
"/>

$myblahs/blah
[/xpath1/xpath2/someintegervalue=position()]/yada

Hmmm, that's not working for me. If I put in a "1" or a
"2" it works, but not with the "variable".

Your example is awfully vague. For better results, provide
a sample XML and a minimum XSLT demonstrating your problem.

Roy,

Here's an example of what I'm referring to. The "does not work"
comment shows what I'm trying to do. The "this does work" shows where
I'm able to hit the nodeset by hardcoding the parameter.

Thanks,
Eric

<page>
<contents>
<ratessummary rec_count="3">
<rate>
<ratecode>1</ratecode>
<myrate>1.1</myrate>
</rate>
<rate>
<ratecode>2</ratecode>
<myrate>1.2</myrate>
</rate>
<rate>
<ratecode>3</ratecode>
<myrate>1.3</myrate>
</rate>
</ratessummary>
<thingsummary rec_count="3">
<thing>
<short_description>Jim</short_description>
<description>James</description>
<thingcode>1</thingcode>
</thing>
<thing>
<short_description>Rick</short_description>
<description>Richard</description>
<thingcode>2</thingcode>
</thing>
<thing>
<short_description>Fred</short_description>
<description>Frederick</description>
<thingcode>3</thingcode>
</thing>
</thingsummary>
</contents>
</page>

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:template match="/">
<html>
<head></head>
<body>
<xsl:apply-templates select="page/contents"></xsl:apply-templates>
</body>
</html>
</xsl:template>
<xsl:template match="contents">
<table>
<tr>
<td class="data">
<xsl:apply-templates select="thingsummary">
<xsl:with-param name="rates"
select="/page/contents/ratessummary"></xsl:with-param>
</xsl:apply-templates>
</td>
</tr>
</table>
</xsl:template>

<xsl:template match="thingsummary">

<xsl:param name="rates"/>

<xsl:value-of select="$rates/rate[1]/org_id"/>

<table>
<xsl:apply-templates select="thing[(position() mod 2)=1]">
<xsl:with-param name="rates" select="$rates"></xsl:with-param>
</xsl:apply-templates>
</table>
</xsl:template>

<xsl:template match="thing[(position() mod 2)=1]">
<xsl:param name="rates"/>
<tr>
<td>
<xsl:value-of select="short_description"/>-<xsl:value-of
select="thingcode"/>-<xsl:value-of select="$rates/rate[1]/org_id"/>
<!-- This does not work-->
test1<xsl:value-of select="$rates/rate[position()=thingcode
]/myrate"/>
<!-- This works-->
test2<xsl:value-of select="$rates/rate[position()=1]/myrate"/>
</td>
<xsl:apply-templates select="following-sibling::thing[1]">
<xsl:with-param name="rates" select="$rates"></xsl:with-param>
</xsl:apply-templates>
</tr>
</xsl:template>
<xsl:template match="thing[(position() mod 2)=0]">
<xsl:param name="rates"/>
<td>
<xsl:value-of select="short_description"/>-<xsl:value-of
select="thingcode"/><xsl:value-of select="$rates/rate[1]/org_id"/>
<!-- This does not work-->
test1<xsl:value-of select="$rates/rate[position()=thingcode
]/myrate"/>
<!-- This works-->
test2<xsl:value-of select="$rates/rate[1]/myrate"/>
</td>
</xsl:template>

</xsl:stylesheet>
 
R

roy axenov

roy said:
Martin Honnen wrote:
(e-mail address removed) wrote:
<xsl:value-of select="
$myblahs/blah
[/xpath1/xpath2/someintegervalue]/yada
"/>

$myblahs/blah
[/xpath1/xpath2/someintegervalue=position()]/yada

Hmmm, that's not working for me. If I put in a "1" or
a "2" it works, but not with the "variable".

Your example is awfully vague. For better results,
provide a sample XML and a minimum XSLT demonstrating
your problem.

Here's an example of what I'm referring to. The "does
not work" comment shows what I'm trying to do. The "this
does work" shows where I'm able to hit the nodeset by
hardcoding the parameter.

You should've read the rest of my post. Your example
confirms that my initial guess was right on money. I ran a
quick test, and the solution I proposed works, too.
<page>
<contents>
<ratessummary rec_count="3">
<rate>
<ratecode>1</ratecode>
<myrate>1.1</myrate>
</rate>
<rate>
<ratecode>2</ratecode>
<myrate>1.2</myrate>
</rate>
<rate>
<ratecode>3</ratecode>
<myrate>1.3</myrate>
</rate>
</ratessummary>
<thingsummary rec_count="3">
<thing>
<short_description>Jim</short_description>
<description>James</description>
<thingcode>1</thingcode>
</thing>
<thing>
<short_description>Rick</short_description>
<description>Richard</description>
<thingcode>2</thingcode>
</thing>
<thing>
<short_description>Fred</short_description>
<description>Frederick</description>
<thingcode>3</thingcode>
</thing>
</thingsummary>
</contents>
</page>
[XSLT]

<xsl:apply-templates select="thingsummary">
<xsl:with-param name="rates"
select="/page/contents/ratessummary"></xsl:with-param>
</xsl:apply-templates>

.. . .
<!-- This does not work-->
test1<xsl:value-of
select="$rates/rate[position()=thingcode]/myrate"/>

So what does it do?

$rates/rate selects a nodeset of <rate> nodes. The
predicate [position()=thingcode] filters this nodeset,
dropping all the nodes that don't have a <thingcode> child
with content that is equal to the position of the <rate>
node in the $rates/rate nodeset. Since there are no <rate>
nodes with <thingcode> children in your document, the
resulting nodeset is, naturally, empty. I already explained
the solution in my previous reply.
 
E

eric.goforth

roy said:
So what does it do?

$rates/rate selects a nodeset of <rate> nodes. The
predicate [position()=thingcode] filters this nodeset,
dropping all the nodes that don't have a <thingcode> child
with content that is equal to the position of the <rate>
node in the $rates/rate nodeset. Since there are no <rate>
nodes with <thingcode> children in your document, the
resulting nodeset is, naturally, empty. I already explained
the solution in my previous reply.

Roy,

I played around with your example, but it doesn't seem to work when I
have multiple xyzzy elements, for example:

<foo>
<bar>
<xyzzy>
<int>3</int>
</xyzzy>
<xyzzy>
<int>4</int>
</xyzzy>
<xyzzy>
<int>5</int>
</xyzzy>
</bar>
<nodeset>
<node>
<str>wrong (1)</str>
<int>3</int>
</node>
<node>
<str>wrong (2)</str>
<int>2</int>
</node>
<node>
<str>right (3)</str>
<int>1</int>
</node>
</nodeset>
</foo>

I'm wondering if it's not possible to do what I'm trying to do.

-Eric
 
J

Joe Kesselman

It really doesn't help us help you when you keep switching element
names, so we can't easily run your new example against your previous
description of the problem. Either pick one set and stick with it, or
post the matched set of sample and failing stylesheet code.
 
J

Joe Kesselman

Your problem is that
$rates/rate[position()=thingcode]/myrate
is looking for a thingcode child of rate -- but of course the thingcode
is child of thing. You're crossing contexts.

The easy way around this is a variable:

<td>
<xsl:value-of select="short_description"/>-<xsl:value-of
select="thingcode"/>-<xsl:value-of select="$rates/rate[1]/org_id"/>
<!-- This does not work because rate has no thingcode-->
test1<xsl:value-of
select="$rates/rate[position()=thingcode]/myrate"/>
<!-- This works-->
test2<xsl:value-of select="$rates/rate[position()=1]/myrate"/>
<!-- This works because we're asking for thingcode in the right
context-->
<xsl:variable name="code" select="thingcode"/>
test3<xsl:value-of select="$rates/rate[position()=$code]/myrate"/>
</td>
 
J

Joe Kesselman

Joe said:
The easy way around this is a variable:

The other way around it would be to say
test3<xsl:value-of
select="$rates/rate[position()=current()/thingcode]/myrate"/>

which says explicitly that you want the thingcode child of the current
XSLT context node (the thing) rather than the context at this point in
the XPath.

The good thing about computers is that they do what you tell them to.
The bad thing about computers is that they do what you tell them to.
 
R

roy axenov

roy said:
So what does it do?

$rates/rate selects a nodeset of <rate> nodes. The
predicate [position()=thingcode] filters this nodeset,
dropping all the nodes that don't have a <thingcode>
child with content that is equal to the position of the
<rate> node in the $rates/rate nodeset. Since there are
no <rate> nodes with <thingcode> children in your
document, the resulting nodeset is, naturally, empty. I
already explained the solution in my previous reply.

I played around with your example, but it doesn't seem to
work when I have multiple xyzzy elements, for example:

<foo>
<bar>
<xyzzy>
<int>3</int>
</xyzzy>
<xyzzy>
<int>4</int>
</xyzzy>
<xyzzy>
<int>5</int>
</xyzzy>
</bar>
<nodeset>
<node>
<str>wrong (1)</str>
<int>3</int>
</node>
<node>
<str>wrong (2)</str>
<int>2</int>
</node>
<node>
<str>right (3)</str>
<int>1</int>
</node>
</nodeset>
</foo>

It *is* working. I'm not sure what the hell you were trying
to do with the input file like this, though.

Pray tell me, what did you expect as a result? It is
supposed to look up the nth <node> in the document for each
<xyzzy>, where n is the value of an <int> child of <xyzzy>
in question. Since there are only *three* <node>s in the
I'm wondering if it's not possible to do what I'm trying
to do.

It's been explained no less than three times in this thread
that what you're trying to do is possible, that your
problem lies in messed-up contexts, that to get the context
of the current node you need to use the current() XPath
function. If you're still unable to grasp that, I recommend
hiring yourself an XSLT expert. Seriously, that'll save you
an awful lot of trouble, time and money.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,005
Messages
2,570,264
Members
46,860
Latest member
JeremiahCo

Latest Threads

Top