Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

xml - Read Mulitple childs and extract data xmlReader in c#

XML :

<InformationTuples>
      <InformationTuple>
       <Name>documentClass</Name>
        <value format="" valueset="{rechnung}" originalValue="Rechnung" start="0" end="0" LD="0" doc="C:4enviam-service-testinputDir31a0933-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:4enviam-service-testinputDir31a0933-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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...