How to get all xpaths from an xml document - c#

How can you get a list of all xpaths from an xml document?
<Tee Surname="Ray" Age="24">
<Login id="51" mid="1" "/>
<Server id="1" mid="144"/>
</Tee>
for example i want to get a list of all xpaths from the above xml

XPath is a search expression. You cannot "get all XPaths" from an XML document. This is like asking for all possible SQL statements from a database.

Related

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#

Iterate through XDocument when you dont know the structure

Is there any way to iterate through a XDocument when you dont know what the XML structure is (using c#)?
There is plenty of examples when you know the structure, like the answer to this question : C# - Select XML Descendants with Linq and C# Foreach XML Node
I've tried Descendants("A") where A is the example below - which in my foreach returns me one element with the name as the root and the value as 'all of the values concatinated into one string'
The reason I'm doing this is to anonymize certain nodes which I know the names.
The XDocument's I'm loading can be of any shape - so i've decided to just create a list which users can add to which contains these sensitive elements.
A solution I want to avoid is users creating XPath's for sensitive fields.
The XML is also sensitive so I cant share online literally but one example (out of 5) would look.
<A>
<B>
<C>
<D>
<dee>value1</dee>
<doo>value2</doo>
<date>value3</date>
<time>value4</time>
</D>
</C>
</B>
<E>
...ommited..this doc is 5000 lines long with 500~ unique node names
</E>
............
</A>
So is there a way to iterate without using Descendants?
Use .Descendants() to iterate every element.
xmlDoc.Root.Descendants()
.ToList()
.ForEach(e => Console.WriteLine(e.Name));
This is the way I went about it.
Descendants means you know the structure of the nodes before hand. Even with an empty method call to descendants (which should get everything from the root) wasn't giving me what I was expecting.
The below code should work for any XML document, without knowing the structure.
XmlDocument doc = new XmlDocument();
doc.Load(file);
using (XmlReader reader = new XmlNodeReader(doc))
{
while (reader.Read())
{
currentNodeName = reader.Name;

Select Nodes with XPath when the XML document contains namespaces

I want to select nodes of a XML document using XPath. But it does not work when the XML document contains xml-namespaces.
How can I search for nodes with XPath considering the namespaces?
This is my XML Document (simplified):
<ComponentSettings xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Company.Product.Components.Model">
<Created xmlns="http://schemas.datacontract.org/2004/07/Company.Configuration">2016-12-14T10:29:28.5614696+01:00</Created>
<LastLoaded i:nil="true" xmlns="http://schemas.datacontract.org/2004/07/Company.Configuration" />
<LastSaved xmlns="http://schemas.datacontract.org/2004/07/Company.Configuration">2016-12-14T16:31:37.876987+01:00</LastSaved>
<RemoteTracer>
<TraceListener>
<Key>f987d7bb-9dea-49b4-a689-88c4452d98e3</Key>
<Url>http://192.168.56.1:9343/</Url>
</TraceListener>
</RemoteTracer>
</ComponentSettings>
I want to get all Url tags of a TraceListener tag of a RemoteTracer tag.
This is how i get them, but this only work if the XML document don't use namespaces:
componentConfigXmlDocument = new XmlDocument();
componentConfigXmlDocument.LoadXml(myXmlDocumentCode);
var remoteTracers = componentConfigXmlDocument.SelectNodes("//RemoteTracer/TraceListener/Url");
Currently, my workaround is to remove all namespaces from the XML raw string using regular expression, before loading the XML. Then my SelectNodes() works fine. But that is no proper solution.
You have two namespaces here. First is
http://schemas.datacontract.org/2004/07/Company.Product.Components.Model
Root element (ComponentSettings), RemoteTracer and everything below it belong to this namespace. Second namespace is
http://schemas.datacontract.org/2004/07/Company.Configuration
Created, LastLoaded and Saved belong to it.
To get the node you need, you have to prefix all elements in your xpath query with their respective namespace prefixes. Mapping of those prefixes to actual namespaces you can do like this:
var componentConfigXmlDocument = new XmlDocument();
componentConfigXmlDocument.LoadXml(File.ReadAllText(#"G:\tmp\xml.txt"));
var ns = new XmlNamespaceManager(componentConfigXmlDocument.NameTable);
ns.AddNamespace("model", "http://schemas.datacontract.org/2004/07/Company.Product.Components.Model");
ns.AddNamespace("config", "http://schemas.datacontract.org/2004/07/Company.Configuration");
And then query like this:
var remoteTracers = componentConfigXmlDocument.SelectNodes("//model:RemoteTracer/model:TraceListener/model:Url", ns);

XPath Query C# to pull out nodes dynamically

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.

How to update an empty node using Xpath navigator

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";

Categories

Resources