为了账号安全,请及时绑定邮箱和手机立即绑定

在C#代码中解析(大)XML的最佳方法是什么?

/ 猿问

在C#代码中解析(大)XML的最佳方法是什么?

郎朗坤 2019-10-17 13:05:40

我正在用C#语言编写GIS客户端工具,以从服务器中检索基于GML的XML模式(以下示例)中的“功能”。提取限制为100,000个功能。


我guestimate,最大的extract.xml可能起床约150兆字节,所以显然DOM解析器是出我一直在试图决定之间的XmlSerializer和XSD.EXE生成绑定-或- 的XmlReader和手工制作的对象图。


或者,也许还有一种我还没有考虑过的更好的方法?像XLINQ还是????


有人可以指导我吗?特别是关于任何给定方法的存储效率。如果不是这样,我将不得不“原型化”这两个解决方案并并排介绍它们。


我对.NET有点不了解。任何指导将不胜感激。


感谢您。基思


XML示例 -最多100,000个,每个功能最多234,600个坐标。


<feature featId="27168306" fType="vegetation" fTypeId="1129" fClass="vegetation" gType="Polygon" ID="0" cLockNr="51598" metadataId="51599" mdFileId="NRM/TIS/VEGETATION/9543_22_v3" dataScale="25000">

  <MultiGeometry>

    <geometryMember>

      <Polygon>

        <outerBoundaryIs>

          <LinearRing>

            <coordinates>153.505004,-27.42196 153.505044,-27.422015 153.503992 .... 172 coordinates omitted to save space ... 153.505004,-27.42196</coordinates>

          </LinearRing>

        </outerBoundaryIs>

      </Polygon>

    </geometryMember>

  </MultiGeometry>

</feature>


查看完整描述

3 回答

?
HUX布斯

使用XmlReader解析大型XML文档。XmlReader提供对XML数据的快速,仅转发,非缓存访问。(仅向前意味着您可以从头到尾读取XML文件,但不能在文件中向后移动。)XmlReader使用少量内存,等效于使用简单的SAX阅读器。


    using (XmlReader myReader = XmlReader.Create(@"c:\data\coords.xml"))

    {

        while (myReader.Read())

        {

           // Process each node (myReader.Value) here

           // ...

        }

    }

您可以使用XmlReader来处理最大2 GB的文件。


查看完整回答
反对 回复 2019-10-17
?
一只甜甜圈

我已改用混合方式...请参见下面的代码。


这个版本具有两者的大多数优点:

  * XmlReader / XmlTextReader(内存效率->速度);和

  * XmlSerializer的(代码根- >发展expediancy和柔韧性)。


它使用XmlTextReader遍历文档,并创建“ doclet”,并使用XmlSerializer和XSD.EXE生成的“ XML绑定”类对它进行反序列化。


我想这个方法是普遍适用的,而且速度很快...我要在7秒钟内解析包含56,000 GML功能的201 MB XML文档...此应用程序的旧VB6实现需要几分钟(甚至几小时)来解析大提取物...所以我很想去。


BIG再次感谢您为宝贵的时间提供宝贵的时间。我真的很感激。


欢呼 基思


using System;

using System.Reflection;

using System.Xml;

using System.Xml.Serialization;

using System.IO;

using System.Collections.Generic;


using nrw_rime_extract.utils;

using nrw_rime_extract.xml.generated_bindings;


namespace nrw_rime_extract.xml

{

    internal interface ExtractXmlReader

    {

        rimeType read(string xmlFilename);

    }


    /// <summary>

    /// RimeExtractXml provides bindings to the RIME Extract XML as defined by

    /// $/Release 2.7/Documentation/Technical/SCHEMA and DTDs/nrw-rime-extract.xsd

    /// </summary>

    internal class ExtractXmlReader_XmlSerializerImpl : ExtractXmlReader

    {

        private Log log = Log.getInstance();


        public rimeType read(string xmlFilename)

        {

            log.write(

                string.Format(

                    "DEBUG: ExtractXmlReader_XmlSerializerImpl.read({0})",

                    xmlFilename));

            using (Stream stream = new FileStream(xmlFilename, FileMode.Open))

            {

                return read(stream);

            }

        }


        internal rimeType read(Stream xmlInputStream)

        {

            // create an instance of the XmlSerializer class, 

            // specifying the type of object to be deserialized.

            XmlSerializer serializer = new XmlSerializer(typeof(rimeType));

            serializer.UnknownNode += new XmlNodeEventHandler(handleUnknownNode);

            serializer.UnknownAttribute += 

                new XmlAttributeEventHandler(handleUnknownAttribute);

            // use the Deserialize method to restore the object's state

            // with data from the XML document.

            return (rimeType)serializer.Deserialize(xmlInputStream);

        }


        protected void handleUnknownNode(object sender, XmlNodeEventArgs e)

        {

            log.write(

                string.Format(

                    "XML_ERROR: Unknown Node at line {0} position {1} : {2}\t{3}",

                    e.LineNumber, e.LinePosition, e.Name, e.Text));

        }


        protected void handleUnknownAttribute(object sender, XmlAttributeEventArgs e)

        {

            log.write(

                string.Format(

                    "XML_ERROR: Unknown Attribute at line {0} position {1} : {2}='{3}'",

                    e.LineNumber, e.LinePosition, e.Attr.Name, e.Attr.Value));

        }


    }


    /// <summary>

    /// xtractXmlReader provides bindings to the extract.xml 

    /// returned by the RIME server; as defined by:

    ///   $/Release X/Documentation/Technical/SCHEMA and 

    /// DTDs/nrw-rime-extract.xsd

    /// </summary>

    internal class ExtractXmlReader_XmlTextReaderXmlSerializerHybridImpl :

        ExtractXmlReader

    {

        private Log log = Log.getInstance();


        public rimeType read(string xmlFilename)

        {

            log.write(

                string.Format(

                    "DEBUG: ExtractXmlReader_XmlTextReaderXmlSerializerHybridImpl." +

                    "read({0})",

                    xmlFilename));


            using (XmlReader reader = XmlReader.Create(xmlFilename))

            {

                return read(reader);

            }


        }


        public rimeType read(XmlReader reader)

        {

            rimeType result = new rimeType();

            // a deserializer for featureClass, feature, etc, "doclets"

            Dictionary<Type, XmlSerializer> serializers = 

                new Dictionary<Type, XmlSerializer>();

            serializers.Add(typeof(featureClassType), 

                newSerializer(typeof(featureClassType)));

            serializers.Add(typeof(featureType), 

                newSerializer(typeof(featureType)));


            List<featureClassType> featureClasses = new List<featureClassType>();

            List<featureType> features = new List<featureType>();

            while (!reader.EOF)

            {

                if (reader.MoveToContent() != XmlNodeType.Element)

                {

                    reader.Read(); // skip non-element-nodes and unknown-elements.

                    continue;

                }


                // skip junk nodes.

                if (reader.Name.Equals("featureClass"))

                {

                    using (

                        StringReader elementReader =

                            new StringReader(reader.ReadOuterXml()))

                    {

                        XmlSerializer deserializer =

                            serializers[typeof (featureClassType)];

                        featureClasses.Add(

                            (featureClassType)

                            deserializer.Deserialize(elementReader));

                    }

                    continue;

                    // ReadOuterXml advances the reader, so don't read again.

                }


                if (reader.Name.Equals("feature"))

                {

                    using (

                        StringReader elementReader =

                            new StringReader(reader.ReadOuterXml()))

                    {

                        XmlSerializer deserializer =

                            serializers[typeof (featureType)];

                        features.Add(

                            (featureType)

                            deserializer.Deserialize(elementReader));

                    }

                    continue;

                    // ReadOuterXml advances the reader, so don't read again.

                }


                log.write(

                    "WARNING: unknown element '" + reader.Name +

                    "' was skipped during parsing.");

                reader.Read(); // skip non-element-nodes and unknown-elements.

            }

            result.featureClasses = featureClasses.ToArray();

            result.features = features.ToArray();

            return result;

        }


        private XmlSerializer newSerializer(Type elementType)

        {

            XmlSerializer serializer = new XmlSerializer(elementType);

            serializer.UnknownNode += new XmlNodeEventHandler(handleUnknownNode);

            serializer.UnknownAttribute += 

                new XmlAttributeEventHandler(handleUnknownAttribute);

            return serializer;

        }


        protected void handleUnknownNode(object sender, XmlNodeEventArgs e)

        {

            log.write(

                string.Format(

                    "XML_ERROR: Unknown Node at line {0} position {1} : {2}\t{3}",

                    e.LineNumber, e.LinePosition, e.Name, e.Text));

        }


        protected void handleUnknownAttribute(object sender, XmlAttributeEventArgs e)

        {

            log.write(

                string.Format(

                    "XML_ERROR: Unknown Attribute at line {0} position {1} : {2}='{3}'",

                    e.LineNumber, e.LinePosition, e.Attr.Name, e.Attr.Value));

        }

    }

}


查看完整回答
反对 回复 2019-10-17
?
蝴蝶刀刀

总结一下,对于任何在google中找到此主题的人来说,答案都更加明显。


在.NET 2之前,XmlTextReader是标准API(thanx Mitch ;-)中可用的内存效率最高的XML解析器。


.NET 2引入了XmlReader类,它再次变得更好。它是一个仅转发元素的迭代器(有点像StAX解析器)。(谢谢脑;-)


记住,小子,任何XML实例都有可能超过500k,不要使用DOM!



查看完整回答
反对 回复 2019-10-17

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信