Search code examples
c#xmlxmlreader

Using XmlReader.ReadToDescendant()


I'm trying to read through an XML (Actually a GML, but I don't think that makes a difference) and have been running into issues with parsing. This is my first brush with dealing in XML.

My code in C#

void ParseXML(String path)
{
    XmlReader reader = XmlReader.Create( new FileStream( path, FileMode.Open ) );

    reader.Read();

    while( reader.Read() )
    {
        // Only detect start elements.
        if ( reader.IsStartElement() && reader.Name == "gml:featureMember" )
        {
            Debug.Log(reader.Name);
            reader.ReadToDescendant("gml:featureMember");
            Debug.Log(reader["ogr:X"]);
        }
    }
}

A section from the GML I'm working with:

  <gml:featureMember>
    <ogr:fence_neighbors fid="F1">
      <ogr:Name>Xyz Xyz</ogr:Name>
      <ogr:X>2353.45361911000</ogr:X>
      <ogr:Y>-4652.36641288000</ogr:Y>
    </ogr:fence_neighbors>
  </gml:featureMember>

Making this slightly more difficult is that I am working without access to System.Xml.Linq (Unity3D). I get reader.Name just fine, but reader["ogr:X"] always comes up null. It seems like I'm not using ReadToDescendant and Reader properly, but I'm not quite sure where to start.


Solution

  • The XmlReader does not know about the namespace prefixes as you're using them.

    Here is a test program that does what I think you're after. Note that the namespace URI is given explicitly.

    using System;
    using System.IO;
    using System.Xml;
    
    
    class SOTest {
    
        static void Main(string[] args) {
            ParseXML(args[0]);
        }
    
        static void ParseXML(String path)
        {
            XmlReader reader = XmlReader.Create( new FileStream( path, FileMode.Open ) );
    
            reader.Read();
    
            while( reader.Read() )
            {
                // Only detect start elements.
                if ( reader.IsStartElement() && reader.LocalName == "featureMember" && reader.NamespaceURI == "gml-namespace-uri" )
                {
                    Console.WriteLine(reader.Name);
                    reader.ReadToDescendant("X", "ogr-namespace-uri");
                    Console.WriteLine(reader.ReadInnerXml());
                }
            }
        }
    }
    

    I added declarations to the source document for testing:

    <?xml version="1.0" encoding="utf-8"?>
    <wrapper xmlns:gml="gml-namespace-uri" xmlns:ogr="ogr-namespace-uri">
      <gml:featureMember>
        <ogr:fence_neighbors fid="F1">
          <ogr:Name>Xyz Xyz</ogr:Name>
          <ogr:X>2353.45361911000</ogr:X>
          <ogr:Y>-4652.36641288000</ogr:Y>
        </ogr:fence_neighbors>
      </gml:featureMember>
    </wrapper>
    

    The output is simply

    gml:featureMember
    2353.45361911000