Reputation: 6015
This is my test XML document:
<?xml version="1.0" encoding="utf-8" ?>
<foos>
<foo>
<bar>
<bazs>
<baz>baz1</baz>
<baz>baz2</baz>
<baz>baz3</baz>
</bazs>
</bar>
</foo>
<!--there will be other foo nodes with same structure but different number of baz nodes-->
</foos>
In this document, each <foo>
node has a single <bar>
node and each <bar>
node has a list of <baz>
nodes. I want to reach these <baz>
nodes from each <bar>
. This is my code:
using System;
using System.Xml;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load("test.xml");
XmlNodeList fooNodes = xmlDocument.SelectNodes("/foos/foo");
foreach(XmlNode fooNode in fooNodes)
{
XmlNode barNode = fooNode.SelectSingleNode("bar");
var bazNodes1 = fooNode.SelectNodes("/bar/bazs/baz");
var bazNodes2 = fooNode.SelectNodes("bar/bazs/baz");
var bazNodes3 = barNode.SelectNodes("/bazs/baz");
Console.WriteLine($"Method 1 returned {bazNodes1.Count} nodes.");
Console.WriteLine($"Method 2 returned {bazNodes2.Count} nodes.");
Console.WriteLine($"Method 3 returned {bazNodes3.Count} nodes.");
}
Console.Read();
}
}
}
, that produces:
Method 1 returned 0 nodes.
Method 2 returned 3 nodes.
Method 3 returned 0 nodes.
Here, I'm a little confused with usage of /
while addressing nodes. While getting fooNodes
from root of the document is working with /foos/foo
as xpath
, but I can't get bazNodes
using /bar/bazs/baz
from a <foo>
node, which is strange to me. And I'm also stuck with getting bazNodes
from a <bar>
node, which I think is because I don't know the correct syntax. So my questions are:
/
when addressing nodes?<baz>
nodes from a <bar>
node in this example?Upvotes: 0
Views: 1562
Reputation: 156
The answer to your first question is if you want to start an absolute path that selects from the root node, you'll need to include a leading "/". The answer for your second question please refer sample code below. In addition, I recommend the article for reference.
using System;
using System.Xml;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var xmlDoc = new XmlDocument();
xmlDoc.Load("test.xml");
XmlNodeList fooNodes1 = xmlDoc.SelectNodes("/foos/foo/bar/bazs/*"); // starts an absolute path that selects from the root
// foos element.
Console.WriteLine($"Method 1 returned {fooNodes1.Count} nodes.");
XmlNodeList fooNodes2 = xmlDoc.SelectNodes("/foos/foo"); // "/foo" the document element(<foo>) of this document.
foreach (XmlNode fooNode in fooNodes2)
{
var bazNodes2 = fooNode.SelectNodes("./bar/bazs/baz"); // "." indicates the current node.
var bazNodes3 = fooNode.SelectNodes("bar/bazs/baz"); // selects all baz elements that are children of an bazs element,
// which is itself a child of the root bar element.
var bazNodes4 = fooNode.SelectNodes("bar/bazs/*"); // "*" selects any element in the path.
var bazNodes5 = fooNode.SelectNodes("bar/*/baz");
var bazNodes6 = fooNode.SelectNodes("//bazs/*"); // selects any elements that are children of an bazs element,
// regardless of where bazs appear in the current context.
var bazNodes7 = fooNode.SelectNodes("bar//baz"); // selects all the baz elements that are under an bar element,
// regardless of where they appear in the current context.
var bazNodes8 = fooNode.SelectNodes("//bazs/baz"); // selects all the bazs elements that are children of an baz element,
// regardless of where they appear in the document.
var bazNodes9 = fooNode.SelectNodes("//baz"); // starts a relative path that selects baz element anywhere.
XmlNode barNode = fooNode.SelectSingleNode("bar");
var bazNodes10 = barNode.SelectNodes("bazs/*"); // selects all nodes which are contained by a root bazs element.
Console.WriteLine($"Method 2 returned {bazNodes2.Count} nodes.");
Console.WriteLine($"Method 3 returned {bazNodes3.Count} nodes.");
Console.WriteLine($"Method 4 returned {bazNodes4.Count} nodes.");
Console.WriteLine($"Method 5 returned {bazNodes5.Count} nodes.");
Console.WriteLine($"Method 6 returned {bazNodes6.Count} nodes.");
Console.WriteLine($"Method 7 returned {bazNodes7.Count} nodes.");
Console.WriteLine($"Method 8 returned {bazNodes8.Count} nodes.");
Console.WriteLine($"Method 9 returned {bazNodes9.Count} nodes.");
Console.WriteLine($"Method 10 returned {bazNodes10.Count} nodes.");
}
Console.Read();
}
}
}
Upvotes: 1
Reputation: 34421
You can do with xml serializer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Foos));
Foos foos = (Foos)serializer.Deserialize(reader);
}
}
[XmlRoot(ElementName = "foos")]
public class Foos
{
[XmlElement("foo")]
public List<Foo> foo { get; set; }
}
[XmlRoot("foo")]
public class Foo
{
[XmlElement("bar")]
public Bar bar { get; set; }
}
[XmlRoot("bar")]
public class Bar
{
[XmlArray("bazs")]
[XmlArrayItem("baz")]
public List<string> baz { get; set; }
}
}
Upvotes: 1