How to: seaching XML child nodes - c#

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"

Related

C# XML merge child node names with parent names and values

I want to merge the names of parent nodes with names of child nodes to bring all to the top level. I don't even know where to start with code on this. I am using C#. I wish to exclude the root node from the merge process.
Example before:
<root>
<lastname>string</lastname>
<firstname>string</firstname>
<student>
<id>string</id>
<ssn>string</ssn>
</student>
</root>
XML after:
<root>
<lastname>string</lastname>
<firstname>string</firstname>
<studentid>string</studentid>
<studentssn>string</studentssn>
</root>
So the student parent has been merged with the id and ssn. Any help would be appreciated if this is even possible.

Select a XML node based on a sibling node

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#

C# Get all nodes in xml document but ignoring nested nodes

I have an xml document where i need to iterate over all nodes that are direct descendants of the parent.
For example i have the following xml document
<root>
<node1>val1</node1>
<node2>val2</node2>
<nodes>
<nestedNode>nestedvalue</nestedNode>
</nodes>
</root>
I have the following code which gets me all the elements:
XmlNodeList nodes = doc.SelectNodes("//*");
This returns node1, node2, and nestedNode. What i want is only node1 and node2 and to ignore any nested values.
Thanks in advance for any help.
To select elements that are children of the root element you would use the xpath:
/root/*
or in general:
/*/*
You should not traverse the all descendants here (//...) as that will go through all elements in the document. You would have to add additional filtering which would make the query unnecessarily complicated:
//*[parent::*[not(parent::*)]]
However, you want to filter out elements that do not have other child elements so you need to add the condition not(*):
/*/*[not(*)]

XElement Replacement when Child Elements and Value Exist

I have some Xml that I am trying to change the name of the XElement on. The XElement contains both child elements and a value similar to this
<parent>
Hi I am a value link
</parent>
I tried using the method suggested here but i can only copy either the elements or the value. Setting the elements first and then the value wipes out the elements.
<newparent>
Hi I am a value link
</newparent>
Copying the value and then elements duplicates the element text
<newparent>
Hi I am a value link link
</newparent>
String manipulation of the value itself escapes all of the brackets.
<newparent>
Hi I am a value link <a href="link">link</a>
</newparent>
Does someone know of a way to achieve the result of copying the value and elements over to the newly created element correctly?
If I get your question correctly, you want all the child nodes copied to a new parent with a different name. If so, use the Nodes() method.
XElement parent = XElement.Parse("<parent>Hi I am a value link</parent>");
var newparent = new XElement("newparent", parent.Nodes());

XPath expression to select all nodes

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>

Categories

Resources