Search code examples
c#xmlxmlreader

XmlReader read continually


I have a very large xml file. This is the simplified version of xml format.

<?xml version='1.0' encoding='UTF-8'?>
<Sender>
 <SenderID>571099948</SenderID>
 <Sponsors>
  <Sponsor>
    <SponsorID>TEST01</SponsorID>
    <Contracts>
      <Contract>
        <ContractID>000001</ContractID>
        <Member>
          <SSN>1111111111</SSN>
          <Gender>M</Gender>
          <Benefits>
            <Benefit BenefitType="AAA">
            </Benefit>
            <Benefit BenefitType="BBB">
            </Benefit>
          </Benefits>
        </Member>
        <Member>
          <SSN>4444444444</SSN>
          <Gender>F</Gender>
          <Benefits>
            <Benefit BenefitType="AAA">
            </Benefit>
          </Benefits>
        </Member>
      </Contract>
      <Contract>
        <ContractID>0000002</ContractID>
        <Member>
          <SSN>2222222222</SSN>
          <Gender>F</Gender>
          <Benefits>
            <Benefit BenefitType="CCC">
            </Benefit>
            <Benefit BenefitType="DDD">
            </Benefit>
          </Benefits>
        </Member>
      </Contract>
      <Contract>
        <ContractID>0000003</ContractID>
        <Member>
          <SSN>333333333</SSN>
          <Gender>F</Gender>
          <Benefits> 
            <Benefit BenefitType="CCC">
            </Benefit>
          </Benefits>
        </Member>
      </Contract>
    </Contracts>
  </Sponsor>
  <Sponsor>
    <SponsorID>TEST02</SponsorID>
    <Contracts>
      <Contract>
        <ContractID>0000011</ContractID>
        <Member>
          <SSN>1111111111</SSN>
          <Gender>M</Gender>
          <Benefits>
          </Benefits>
        </Member>
      </Contract>
      <Contract>
        <ContractID>0000002</ContractID>
        <Member>
          <SSN>2222222222</SSN>
          <Gender>F</Gender>
          <Benefits>
          </Benefits>
        </Member>
      </Contract>
    </Contracts>
  </Sponsor>
</Sponsors>
</Sender>

I want get all information of contract node, as well as SponsorID from the parent node. Here is the code to partially read xml file using XmlReader:

        static IEnumerable<XElement> SimpleStreamAxis(string inputUrl, string elementName)      
    {

            using (XmlReader reader = XmlReader.Create(inputUrl))
            {
                reader.MoveToContent();
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        if (reader.Name == elementName)
                        {
                            XElement el = XNode.ReadFrom(reader) as XElement;
                            if (el != null)
                            {
                                yield return el;
                            }
                        }
                    }
                }
            }                  
    }

Here is the issue. I cannot use this, because the whole sponsor tree may be too large for the memory.

var sponsor = SimpleStreamAxis(file, "Sponsor");

I cannot use this either, because I cannot tell SponsorID with only Contract node info.

var contract = SimpleStreamAxis(file, "Contract");

Is there a way that I can read the SponsorID in Sponsor, move cursor forward, and read all the Contract nodes under this Sponsor, then move to next Sponsor and read SponsorID and its Contract nodes and so on?


Solution

  • Try this:

    using (XmlReader xmlReader = XmlReader.Create("file.xml"))
    {
        while (xmlReader.Read())
        {
            if (xmlReader.ReadToFollowing("SponsorID"))
            {
                string sponsorId = xmlReader.ReadElementContentAsString();
    
                // process SponsorID
                Console.WriteLine(sponsorId);
    
                if (xmlReader.ReadToFollowing("Contract"))
                {
                    do
                    {
                        XmlReader contractSubtree = xmlReader.ReadSubtree();
                        XElement contractElement = XElement.Load(contractSubtree);
    
                        // process Contract
                        Console.WriteLine(contractElement.Element("ContractID"));
    
                    } while (xmlReader.ReadToNextSibling("Contract"));
                }
            }
        }
    }