Navigating by attribute in XPath

  • Thread starter Thread starter jon cosby
  • Start date Start date
J

jon cosby

This code shows all values for the config node. I'm trying to retrieve
the value for systrayenabled for attrib "jon". Something wrong?


sXmlPath = Application.StartupPath.ToString() + "\\settings.xml";
XmlDocument xmlConfig = new XmlDocument();
xmlConfig.Load(sXmlPath);
XPathNavigator navigator = xmlConfig.CreateNavigator();

XPathNodeIterator iterator =
navigator.Select("timer/config[@user='jon']/systrayenabled");
MessageBox.Show(iterator.Current.Value);
 
Hello Jon,

What's the problem?
I'd be better if you showed you xml

JC> This code shows all values for the config node. I'm trying to
JC> retrieve the value for systrayenabled for attrib "jon". Something
JC> wrong?
JC>
JC> sXmlPath = Application.StartupPath.ToString() + "\\settings.xml";
JC> XmlDocument xmlConfig = new XmlDocument();
JC> xmlConfig.Load(sXmlPath);
JC> XPathNavigator navigator = xmlConfig.CreateNavigator();
JC> XPathNodeIterator iterator =
JC> navigator.Select("timer/config[@user='jon']/systrayenabled");
JC> MessageBox.Show(iterator.Current.Value);
JC>
---
WBR,
Michael Nemtsev :: blog: http://spaces.msn.com/laflour

"At times one remains faithful to a cause only because its opponents do not
cease to be insipid." (c) Friedrich Nietzsche
 
Michael said:
Hello Jon,

What's the problem?
I'd be better if you showed you xml

JC> This code shows all values for the config node. I'm trying to
JC> retrieve the value for systrayenabled for attrib "jon". Something
JC> wrong?
JC>
JC> sXmlPath = Application.StartupPath.ToString() + "\\settings.xml";
JC> XmlDocument xmlConfig = new XmlDocument();
JC> xmlConfig.Load(sXmlPath);
JC> XPathNavigator navigator = xmlConfig.CreateNavigator();
JC> XPathNodeIterator iterator =
JC> navigator.Select("timer/config[@user='jon']/systrayenabled");
JC> MessageBox.Show(iterator.Current.Value);
JC>
---
WBR,
Michael Nemtsev :: blog: http://spaces.msn.com/laflour

"At times one remains faithful to a cause only because its opponents do not
cease to be insipid." (c) Friedrich Nietzsche


The output is all of the values for the config nodes for all users. I
am trying to retrieve a single value for "jon".


<timer>
<config user="default">
<systrayenabled>false</systrayenabled>
<systraytimer>1</systraytimer>
<logevents>false</logevents>
</config>
<config user="jon">
<systrayenabled>true</systrayenabled>
<systraytimer>1</systraytimer>
<logevents>false</logevents>
</config>
</timer>
 
The output is all of the values for the config nodes for all users. I
am trying to retrieve a single value for "jon".

I suspect you're making things harder than you need to by using
XPathNavigator. I find it's usually easier to use SelectSingleNode on
the document (or element). Here's a sample:

using System;
using System.Xml;
using System.Xml.XPath;

class Test
{
static void Main()
{
string xml = @"
<timer>
<config user='default'>
<systrayenabled>false</systrayenabled>
<systraytimer>1</systraytimer>
<logevents>false</logevents>
</config>
<config user='jon'>
<systrayenabled>true</systrayenabled>
<systraytimer>1</systraytimer>
<logevents>false</logevents>
</config>
</timer>
";
XmlDocument doc = new XmlDocument();
doc.LoadXml (xml);

XmlNode node = doc.SelectSingleNode("timer/config
[@user='jon']/systrayenabled");
Console.WriteLine (node.OuterXml);
}
}

Now, as to why it wasn't working for you: from the docs of
XPathNodeIterator:

<quote>
An XPathNodeIterator object returned by the XPathNavigator class is not
positioned on the first node in a selected set of nodes. A call to the
MoveNext method of the XPathNodeIterator class must be made to position
the XPathNodeIterator object on the first node in the selected set of
nodes.
</quote>

And indeed if you call MoveNext() before printing the result, you'll
find you get the results you expect. I'd still use SelectSingleNode
though :)
 
Jon said:
The output is all of the values for the config nodes for all users. I
am trying to retrieve a single value for "jon".

I suspect you're making things harder than you need to by using
XPathNavigator. I find it's usually easier to use SelectSingleNode on
the document (or element). Here's a sample:

using System;
using System.Xml;
using System.Xml.XPath;

class Test
{
static void Main()
{
string xml = @"
<timer>
<config user='default'>
<systrayenabled>false</systrayenabled>
<systraytimer>1</systraytimer>
<logevents>false</logevents>
</config>
<config user='jon'>
<systrayenabled>true</systrayenabled>
<systraytimer>1</systraytimer>
<logevents>false</logevents>
</config>
</timer>
";
XmlDocument doc = new XmlDocument();
doc.LoadXml (xml);

XmlNode node = doc.SelectSingleNode("timer/config
[@user='jon']/systrayenabled");
Console.WriteLine (node.OuterXml);
}
}

Now, as to why it wasn't working for you: from the docs of
XPathNodeIterator:

<quote>
An XPathNodeIterator object returned by the XPathNavigator class is not
positioned on the first node in a selected set of nodes. A call to the
MoveNext method of the XPathNodeIterator class must be made to position
the XPathNodeIterator object on the first node in the selected set of
nodes.
</quote>

And indeed if you call MoveNext() before printing the result, you'll
find you get the results you expect. I'd still use SelectSingleNode
though :)

That works, but I'm using the XPathNavigator to modify the xml
document. I can navigate with a "MoveToChild/MoveToNext" sequence, but
I can't query values.
 
Jon Cosby said:
That works, but I'm using the XPathNavigator to modify the xml
document.

Any reason not to modify the DOM model directly?
I can navigate with a "MoveToChild/MoveToNext" sequence, but
I can't query values.

If you call MoveNext() with the code you provided, then
iterator.Current.Value prints out "true" which is what you want, isn't
it?
 
Jon said:
Any reason not to modify the DOM model directly?


If you call MoveNext() with the code you provided, then
iterator.Current.Value prints out "true" which is what you want, isn't
it?

Not exactly what I meant. I need something like

navigator.MoveToNode("timesynch/config[@user='jon']/systrayenabled");
navigator.SetValue("Okay");
 
Jon Cosby said:
Not exactly what I meant. I need something like

navigator.MoveToNode("timesynch/config[@user='jon']/systrayenabled");
navigator.SetValue("Okay");

So why not use SelectSingleNode (specifying the text node) and then set
the value to "Okay"?

Anyway, if you *do* genuinely need to use XPathNavigator, calling
MoveNext() to start with after calling Select should set you straight.
 

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

Back
Top