I'm trying to select an XML node, where another child of the parent node contains a specific value.
The XML looks like this:
<?xml version="1.0" encoding="UTF-8" ?>
<AuthorIT>
<Objects>
<Media>don't care</Media>
<Style>don't care</Style>
<Book>don't care</Book>
<Topic>don't care</Topic>
<Topic>
<Object>
<Description>Performance Evidence</Description>
</Object>
<Text>This is what I want to select</Text>
</Topic>
</Objects>
</AuthorIT>
I'm using XPath in C#. My query at the moment looks like this: (but doesn't work, obviously)
docNav = new XPathDocument(localFile);
nav = docNav.CreateNavigator();
xPath = "//Topic[Object/Description = 'Performance Evidence']/Text";
string value = nav.SelectSingleNode(xPath).Value;
How do I get the contents of the Text node, from the Topic that has an Object/Description value of "Performance Evidence"?
You should first select the Description node containing your needle text, then move back to the common parent and select the Text nodes that are its children.
//Topic/Object/Description[text()='Performance Evidence']/../../Text/text()
As Kirill Polishchuk said in a comment, my XPath was correct.
What I left out of the example XML was the key to the solution... Namespace!
I found my answer on this other question: Using Xpath With Default Namespace in C#
Related
I have problem to select second node from root element in following example xml code:
<?xml version="1.0"?>
<config>
<FirstNode>
<ShowBlahBlah>
</ShowBlahBlah>
</FirstNode>
<SecondNode>
<ShowBlahBlah>
</ShowBlahBlah>
</SecondNode>
</config>
and using this C# code to select SecondNode:
XmlDocument doc = new XmlDocument();
doc.LoadXml(sReadXML);
XmlNode sChangesLog = doc.SelectSingleNode("config").SelectSingleNode("//SecondNode").SelectSingleNode("//ShowBlahBlah")
XmlNodeList sChildNodes = sChangesLog.ChildNodes;
but it selecting first node and return its value!
how can I fix this problem?
You're using // at the start of each of your selections - which means "find descendant nodes starting at the root" (so the context is irrelevant). You could either do things in one step as per Jeffrey's answer, or use relative paths:
doc.SelectSingleNode("config")
.SelectSingleNode("SecondNode")
.SelectSingleNode("ShowBlahBlah")
Personally I'd use LINQ to XML instead, if at all possible:
var doc = XDocument.Parse(sReadXml);
var changes = doc.Root.Element("SecondNode").Element("ShowBlahBlah");
LINQ to XML is generally a much cleaner API than XmlDocument et al.
I am having to write a XPath Query to pull out the answer for a question based on the question id. The question id is passed dynamically to the query. I cannot use LINQ as the solution is in NET 2.0. Please find the XML file below
<?xml version="1.0" encoding="utf-8" ?>
<Questionaire>
<question id="1">
<answer>1</answer>
<correctAnswer>Text</correctAnswer>
</question>
<question id="2">
<answer>2</answer>
<correctAnswer>Text</correctAnswer>
</question>
</Questionaire>
I'am a novice to XPath and find it hard to get my head around it.
Many thanks in advance.
You could use the XmlDocument class and the SelectSingleNode method to perform XPath queries. You may checkout the following article for examples. In your case the XPath query will be something along the lines of Questionaire/question[id='1'] where the id could be variable of course in order to fetch the corresponding node. Once you find the <question> node corresponding to your search criteria you could navigate to its child nodes.
Your XPath expression can be dynamically generated like this:
myExpression = string.Format("/*/*[id='{0}']/answer", theId);
then, depending on the object representing the XML document you need to call one of the following methods: Select(), SelectNodes(), SelectSingleNode(), Evaluate().
Read the MSDN documentation about the appropriate methods of XmlDocument, XPathDocument, XPathNavigator and XPathExpression.
I would like to find all <Field /> nodes (that may be arbitrarily nested) inside a given XmlNode.
If do something like this:
foreach(XmlNode n in node.SelectNodes('//Field'))...
This returns all nodes in the entire document, not all nodes under node.
Is this how XPath is supposed to work? I looked at some documents and it seems like the //Node query should be scoped to whatever node it's invoked at.
Is there any other technique to select all nodes with a given name that are under a specific node?
If you use '//Field' it's absolut from the root of the document. To search relative to the current node, just use './/Field'.
Use ./Field.
.// Means descendants, which includes children of children (and so forth).
./ Means direct children.
If a XPath starts with a / it becomes relative to the root of the document; to make it relative to your own node start it with ./.
try to use SelecteSingleNode()
Remove // because otherwise it search among all the document irrelatively to the root node.
node.SelectNodes("Field")
You can use simple linq query like this:
var techLeads = (from value in element.Descendants ("Manager")
where value.Attribute ("Name").Value == "Mgr1"
select value).Descendants("TechLead");
Sample Xml:
<Employees>
<Manager Name="Mgr1">
<TechLead Name="TL1" />
<TechLead Name="TL2" />
</Manager>
</Employees>
i have an XML like this
<main>
<reportPath>d:\reports</reportPath>
<errorPath>D:\Error</errorPath>
<project>D:\xyz.txt</project>
<value />
</main>
here "value" is an empty node. using Xpath navigator, I am able to reach Value node, but not able update it.
using something like :
XPathNavigator currentnavigator = navigator.SelectSingleNode("//*/value");
Can anyone give me some idea how to edit this node i.e. add value to it which can be a string path.
will get appended at the end ?
If your navigator is editable, you can just use SetValue():
currentnavigator.SetValue("somePath");
That being said, I would recommend you to use LINQ to XML instead, I find it much easier to use:
XDocument doc = …;
doc.Root.Element("value").Value = "somePath";
Given a piece of Xml Like the one below. How would I write an XPATH Query to get the value of the 'leaf2' child where the 'key' value has a particular values (say 2)
I'm working in C# .NET. At the moment I'm just looking at getting the Xpath for key using SelectNodes , finding the right value then navigating back up to leaf2.
<root>
<child>
<anotherChild>
<key>1</key>
</anotherChild>
<leaf1>X</leaf1>
<leaf2>Y</leaf2>
<leaf3></leaf3>
</child>
<child>
<anotherChild>
<key>2</key>
</anotherChild>
<leaf1>A</leaf1>
<leaf2>B</leaf2>
<leaf3></leaf3>
</child>
</root>
You want:
/root/child[anotherChild/key = '2']/leaf2
This is saying, "get elements named leaf2, whose parent is child and whose grandparent is root, where child is being filtered by its child named anotherChild with a child named key whose value is 2."
Or, perhaps a bit more flexibly because it doesn't assume the grandfather is root
//child/anotherChild/key[text()="2"]/../../leaf2
"find the key with text 2, parent anotherChild and grandparentchild, go to grandparent(i.e. child, and find leaf2"