5

I have following XML:

<Loop Name="MasterData">
  <Loop Name="SlaveData">
    <Segment Name="AAA">
      <Node1>hello</Node1>
      <Node2>john</Node2>
      <Node3>hi</Node3>
      <Node4>marry</Node4>
    </Segment>
    <Segment Name="BBB">
      <Node1>00</Node1>
      <Node2> </Node2>
      <Node3>00</Node3>
      <Node4> </Node4>
    </Segment> 
   </Loop>
</Loop>

I have to read value of each Node i.e, Node1, Node2, Node3, Node4 which are under Segment node whose attribute ie Name = "AAA". How can I do this. I am referring following link from stackoverflow but thats not working for me.

How to read attribute value from XmlNode in C#?

I need output like this

Lets I have four sting variables strNode1, strNode2, strNode3, strNode4. I want to store values in above four variables like following

strNode1 = "hello"
strNode2 = "john"
strNode3 = "hi"
strNode4  = "marry"
Community
  • 1
  • 1

9 Answers9

8

You could use XmlDocument to load your xml as an object and then query the specific nodes you want using XPath. Your xpath query (which I can't test right now) would probably look like this.

XmlNodeList xNodes = xmlDocument.SelectNodes("//Segment[@Name = 'AAA']");
phadaphunk
  • 12,785
  • 15
  • 73
  • 107
  • `SelectNodes` returns an `XmlNodeList`, not an `XmlNode`. – Thorsten Dittmar Apr 22 '13 at 13:49
  • you can go one step further in the XPath since OP only wants the innerText using the node() function and the Cast XLinq function. I.e. dom.SelectNodes("//Segment[@Name = 'AAA']/node()").Cast().Select(n => n.InnerText).ToList() – an phu Jul 15 '15 at 19:16
6

I found a simple solution for my problem

XmlNodeList xnList = doc.SelectNodes("/Loop/Loop/Segment[@Name='AAA']");
          foreach (XmlNode xn in xnList)
          {
              if (xn.HasChildNodes)
              {
                  foreach (XmlNode item in xn.ChildNodes)
                  {
                      Console.WriteLine(item.InnerText);
                  }
              }  
          }
4

I'd recommend using an XDocument (NB specific filtering based on parent nodes etc omitted):

var document = XDocument.Load(path);
var nodes = document.Descendents().Where(e => e.Name.LocalName.StartsWith("Node"));

Update to include filtering of parent element

var nodes = document.Descendents()
                    .Where(e => e.Atrributes().Any(a => a.Name.localName == "Name" && a.Value == "AAA"))
                    .SelectMany(e => e.Descendents().Where(e => e.Name.LocalName.StartsWith("Node"));
var values = nodes.Select(n => n.Value).ToList(); // This will be a list containing "hello", "john, "hi", "marry"
Rich O'Kelly
  • 41,274
  • 9
  • 83
  • 114
  • 2
    I have to read Node1,Node2, Node3, Node4 which are under segment whose Name = "AAA". I think your solution will try to read all Node elements –  Apr 22 '13 at 12:33
  • Have you consider the filtering? – Hossein Narimani Rad Apr 22 '13 at 12:39
  • Answer now updated to include the filtering and selection of values. NB Very few assumptions are made about the structure of the xml, all elements that are descendents of an element who has a name attribute of "AAA" are eligible, rather than just those that fall under the `Loop -> Loop -> Segment` hierarchy – Rich O'Kelly Apr 22 '13 at 14:07
3

Assuming you have an XmlDocument you can use XPath like:

XmlNode node = doc.SelectSingleNode("//Segment[@Name='AAA']");

to get the Segment node and then iterate all its children in a loop.

Thorsten Dittmar
  • 55,956
  • 8
  • 91
  • 139
2

Try this:

System.Xml.Linq.XDocument doc = XDocument.Load(your file);

var nodes = 
     doc.Element("Loop").Element("Loop").Elements("Segment")
                .Where(input => (string)input.Attribute("Name") == "AAA")
                .Select(input => input.Elements()).ToList();

Then:

List<string> result = new List<string>();

foreach (List<XElement> item in nodes)
{
    result.AddRange(item.Select(i => i.Value));
}
Hossein Narimani Rad
  • 31,361
  • 18
  • 86
  • 116
  • 2
    Use `(string)input.Attribute("Name") == "AAA"` instead. Your code will throw an exception if there exists at least one `Segment` node without a `"Name"` attribute. – Daniel Hilgarth Apr 22 '13 at 12:39
  • @HosseinNarimaniRad - thanks its working, but how can loop through all the nodes selected to get values of all those in a string? –  Apr 22 '13 at 12:55
  • @NareshKumar Edit your post and consider writing the string output you expect to reach. – Hossein Narimani Rad Apr 22 '13 at 12:56
  • @HosseinNarimaniRad - I have edited my post. Basically I wanted to know how do I iterate elements in nodes variable using foreach loop? –  Apr 22 '13 at 13:01
2

You could use XmlDocument and XPath:

XmlDocument doc = new XmlDocument();
doc.Load(xml);
foreach(XmlNode node in doc.SelectNodes("//Segment[@Name='AAA']/node()"))
{
    string name = node.Name;
    string value = node.innerText;
    // ...
}
Casperah
  • 4,504
  • 1
  • 19
  • 13
  • Since OP only wants the innerText, you can make the foreach statement more concise by casting the XmlNodeList into a IEnumerable and then projecting out the InnerText, i.e. dom.SelectNodes("//Segment[@Name = 'AAA']/node()").Cast().Select(n => n.InnerText).ToList() – an phu Jul 15 '15 at 19:18
0

If you ever used linq-to-entities or linq-to-sql, there is a linq-to-xml you can use.

Erwin
  • 3,060
  • 26
  • 24
0

Do you can try this ?

XDocument xmlFile = XDocument.Load("myFile.xml");
foreach (var nodeSegment in xmlFile.Descendants("Loop"))
{
   foreach (var nodes in nodeSegment.Descendants().Where(e => e.Name.LocalName.StartsWith("Node")))
   {

   }
}
Mehdi Bugnard
  • 3,889
  • 4
  • 45
  • 86
0

Try this out..

List<string> nodeDetails = new List<string>();

       var nodes = from n in XDocument.Load(@"D:\pfXml.xml")
                                              .Element("Loop")
                                              .Element("loop")
                                              .Elements("Segment")
                                      where (string)n.Attribute("Name") == "AAAA"
                                      select new
                                      {
                                          n1 = n.Element("Node1").Value,
                                          n2 = n.Element("Node2").Value,
                                          n3 = n.Element("Node3").Value,
                                          n4 = n.Element("Node4").Value
                                      };
        foreach (var node in nodes)
        {
            nodeDetails.Add(node.n1);
            nodeDetails.Add(node.n2);
            nodeDetails.Add(node.n3);
            nodeDetails.Add(node.n4);
        }
Asif Iqbal
  • 531
  • 8
  • 28