0

XML :

<InformationTuples>
      <InformationTuple>
       <Name>documentClass</Name>
        <value format="" valueset="{rechnung}" originalValue="Rechnung" start="0" end="0" LD="0" doc="C:\b4enviam-service-test\inputDir\031a0933-2616-4d8e-8a79-56746ae0e160/Invoice_51029062.pdf">Rechnung</value>
        <EntityType>Class</EntityType>
        <state>New       </state>
        <need>Mandatory </need>
        <extractionmethod>
        </extractionmethod>
        <weight>1</weight>
        <precondition type="optional">All</precondition>
      </InformationTuple>
      <InformationTuple>
        <Name>SAPNr.</Name>
        <value format="" valueset="" originalValue="4352020616" start="0" end="0" LD="0" doc="C:\b4enviam-service-test\inputDir\031a0933-2616-4d8e-8a79-56746ae0e160/Invoice_51029062.pdf">4352020616</value>
        <EntityType>KB.GTInovice</EntityType>
        <state>New       </state>
        <need>Mandatory </need>
        <extractionmethod>
        </extractionmethod>
        <weight>1</weight>
        <precondition type="optional">all</precondition>
      </InformationTuple>
      <InformationTuple>
        <Name>GT-Invoice</Name>
        <value format="" valueset="" originalValue="" start="0" end="0" LD="0" doc="">
        </value>
        <EntityType>KB.GTInovice</EntityType>
        <state>New       </state>
        <need>Mandatory </need>
        <extractionmethod>
        </extractionmethod>
        <weight>1</weight>
        <precondition type="optional">all</precondition>
      </InformationTuple>
    </InformationTuples>

C#

reader.ReadToFollowing("InformationTuple");
                   reader2.ReadToFollowing("InformationTuple");



                   do
                   {
                       subtree = reader2.ReadSubtree();
                       subtree.ReadToFollowing("Name");
                       Debug.WriteLine(subtree.ReadElementContentAsString());
                       reader2.ReadToNextSibling("InfromationTuple");



                   } while (reader.ReadToNextSibling("InformationTuple"))

I'm trying for a while now to extract data from multiple childs in XML using c# but didn't successful. I have tried multiple code snippets but unable to extract data.

Like i have to extract the data given in three information tuples, but functions given in the XMLreader not working properly reader pointer break after single loop iteration (unable to move to second InformationTuple), even i have tried two different reader pointer but its now giving exception.

Need little help , Thanks

zfar
  • 23
  • 3
  • For this purpose, i highly recommend to use [Linq2Xml](http://stackoverflow.com/questions/670563/linq-to-read-xml) – lokusking Jul 17 '16 at 19:32

2 Answers2

1

You can read the first <Name> element inside each <InformationTuple> as follows. Introduce the following extension methods:

public static partial class XmlReaderExtensions
{
    public static IEnumerable<string> ReadAllElementContentsAsString(this XmlReader reader, string localName, string namespaceURI)
    {
        while (reader.ReadToFollowing(localName, namespaceURI))
            yield return reader.ReadElementContentAsString();
    }

    public static IEnumerable<XmlReader> ReadAllSubtrees(this XmlReader reader, string localName, string namespaceURI)
    {
        while (reader.ReadToFollowing(localName, namespaceURI))
            using (var subReader = reader.ReadSubtree())
                yield return subReader;
    }
}

And then do:

foreach (var name in reader.ReadAllSubtrees("InformationTuple", "")
    .Select(r => r.ReadAllElementContentsAsString("Name", "").First()))
{
    // Process the name somehow
    Debug.WriteLine(name);
}

If you want to only read the first <Name> element of each <InformationTuple> element inside each <InformationTuples> container, you can restrict the scope of the search by composing calls to ReadAllSubtrees() using SelectMany():

foreach (var name in reader.ReadAllSubtrees("InformationTuples", "")
    .SelectMany(r => r.ReadAllSubtrees("InformationTuple", ""))
    .Select(r => r.ReadAllElementContentsAsString("Name", "").First()))
{
    // Process the name somehow
    Debug.WriteLine(name);
}

Some notes:

  • You don't close (or dispose) your ReadSubtree() subtree reader when you are done with it. From the docs:

    You should not perform any operations on the original reader until the new reader has been closed. This action is not supported and can result in unpredictable behavior.

    Thus you must close or dispose this nested reader before advancing the outer reader.

  • You have too many calls to reader.ReadToFollowing("InformationTuple"); at the beginning. Perhaps you meant to do reader.ReadToFollowing("InformationTuples");?

  • To ensure there is one and only one <Name> element for each <InformationTuple> replace First() with .Single().

  • If there might be multiple <Name> nodes for each <InformationTuple> and you want to read all of them, do:

    foreach (var name in reader.ReadAllSubtrees("InformationTuple", "")
        .SelectMany(r => r.ReadAllElementContentsAsString("Name", "")))
    {
        // Process the name somehow
    

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • Thanks man, you notes have solved my problem , thanks again :) – zfar Jul 18 '16 at 20:15
  • @zfar - you're welcome. If the question is answered, please do [mark it as such](https://meta.stackexchange.com/questions/147531/how-mark-my-question-as-answered-on-stackoverflow). – dbc Jul 18 '16 at 20:23
0

The code below I used a lot and will not create any errors.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XmlReader reader = XmlReader.Create(FILENAME);
            while (!reader.EOF)
            {
                if (reader.Name != "InformationTuple")
                {
                    reader.ReadToFollowing("InformationTuple");
                }
                if (!reader.EOF)
                {
                    XElement subtree = (XElement)XElement.ReadFrom(reader);
                    Info.info.Add(new Info() { state = (string)subtree.Element("state"), weight = (int)subtree.Element("weight") });
                }
            }
        }
    }
    public class Info
    {
        public static List<Info> info = new List<Info>();
        public string state { get; set; }
        public int weight { get; set; }

    }
}
jdweng
  • 33,250
  • 2
  • 15
  • 20
  • Thanks lot , here is a thing that i have to extract information from "name" , "State" and "weight" from all of the given Information Tuple. its quite similar to book example where you given multiple books and each book tag is entitle with its own information (name , author etc) and task to extract each book information – zfar Jul 18 '16 at 19:40