代码之家  ›  专栏  ›  技术社区  ›  Jeff Yates

在C中优化XML#

  •  5
  • Jeff Yates  · 技术社区  · 15 年前

    背景

    我们有一个项目在.NET 1.1中启动,移到.NET 2.0,最近又移到.NET 3.5。这个项目是非常数据驱动的,并且对它的许多数据文件使用XML。其中一些XML文件非常大,我想借此机会改进应用程序与它们的交互。如果可能的话,我希望避免在任何时候都将它们完全保存在内存中,但另一方面,我希望能够快速访问它们的数据。

    当前设置使用 XmlDocument XPathDocument (取决于写的时间和作者)。当第一次请求数据并将其缓存在内部数据结构(而不是XML,在大多数情况下,XML将占用更多的内存)中时,将查找数据。在过去,这是一个很好的模型,因为它具有快速的访问时间和较低的内存占用(或者至少是令人满意的内存占用)。然而,现在有一个特性可以一次查询大部分信息,而不是像我们以前那样很好地分散请求。这会导致XML加载、验证和解析成为性能方面的明显瓶颈。

    问题

    对于大型XML文件,查询其内容的最有效和最快速的方法是什么(例如,“id=b的元素a是否存在?”)在内存中没有XML的情况下重复?

    请注意,数据本身可以在内存中,如果我们能帮助的话,它就不能以更膨胀的XML形式存在。在最坏的情况下,我们可以接受将单个文件加载到内存中进行解析,然后再次卸载以释放资源,但如果可能的话,我希望避免这种情况。

    考虑到我们已经在尽可能地缓存数据,这个问题也可以理解为“更快、占用更少内存; XML文档 , XPATH文档 ,分析基于 XmlReader XDocument / LINQ-to-XML

    编辑: 更简单的是,我们可以在不同时读取整个文件的情况下随机访问磁盘上的XML吗?

    例子

    XML文件有一些记录:

    <MyXml>
      <Record id='1'/>
      <Record id='2'/>
      <Record id='3'/>
    </MyXml>
    

    我们的用户界面想知道是否存在ID为3的记录。如果可以的话,我们想在不需要解析和加载文件中的每个记录的情况下找到答案。所以,如果它在我们的缓存中,就没有XML交互,如果没有,我们可以将记录加载到缓存中并响应请求。

    目标

    拥有一种可扩展的、快速的查询和缓存XML数据文件的方法,以便我们的用户界面能够响应,而无需使用多个线程或将整个XML文件长期保留在内存中。

    我知道在某个地方可能会有一篇关于这个的博客或msdn文章,在我发布这个问题之后,我会继续使用google,但是如果有人有一些可能有用的数据,或者某个方法比另一种更好或更快的例子,那就太好了。


    更新
    The XMLTeam published a blog today 这对于何时在.NET中使用各种XML API提供了很好的建议。它看起来像是基于 XMLRead IEnumerable 对于我在这里给出的场景,这将是我最好的选择。

    6 回复  |  直到 9 年前
        1
  •  2
  •   mcauthorn    15 年前

    对于XML,我只知道两种方法

    xmlReader->将大型XML数据传输到 或者使用XMLDOM对象模型,将整个XML一次读取到内存中。

    如果XML很大,那么我们有80MB以上的XML文件,将XML读取到内存中会影响性能。没有真正的方法可以“合并”处理XML文档的两种方法。对不起的。

        2
  •  2
  •   nawfal Donny V.    9 年前

    不久前,我在尝试传输XML时遇到了这篇白皮书: API-based XML streaming with FLWOR power and functional updates 本文尝试使用内存中的XML,但利用了LINQ访问。

    也许有人会觉得有趣。

        3
  •  1
  •   shahkalpesh    15 年前

    这听起来可能很愚蠢。
    但是,如果您有一些简单的东西需要查询,那么可以在XML文件上使用regex。(他们在Unix/Linux中做grep的方式)。

    如果没有任何意义,我道歉。

        4
  •  0
  •   Alexander Kahoun    15 年前

    问题的第一部分听起来像是模式验证最有效。如果您有权访问XSD或可以创建它们,您可以使用类似的算法:

        public void ValidateXmlToXsd(string xsdFilePath, string xmlFilePath)
        {
            XmlSchema schema = ValidateXsd(xsdFilePath);
            XmlDocument xmlData = new XmlDocument();
            XmlReaderSettings validationSettings = new XmlReaderSettings();
    
            validationSettings.Schemas.Add(schema);
            validationSettings.Schemas.Compile();
            validationSettings.ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema;
            validationSettings.ValidationType = ValidationType.Schema;
            validationSettings.ValidationEventHandler += new ValidationEventHandler(ValidationHandler);
            XmlReader xmlFile = XmlReader.Create(xmlFilePath, validationSettings);
    
            xmlData.Load(xmlFile);
            xmlFile.Close();
        }
    
        private XmlSchema ValidateXsd(string xsdFilePath)
        {
            StreamReader schemaFile = new StreamReader(xsdFilePath);
            XmlSchema schema = XmlSchema.Read(schemaFile, new ValidationEventHandler(ValidationHandler));
            schema.Compile(new ValidationEventHandler(ValidationHandler));
            schemaFile.Close();
            schemaFile.Dispose();
    
            return schema;
        }
    
        private void ValidationHandler(object sender, ValidationEventArgs e)
        {
            throw new XmlSchemaException(e.Message);
        }
    

    如果XML无法验证 XmlSchemaException 被扔掉。

    至于Linq,我个人更喜欢使用 XDocument 只要我能结束 XmlDocument . 你的目标有点主观,如果不知道你在做什么,我不能肯定地说,走这条路或走那条路会对你有所帮助。可以将xpath与 X文档 . 我不得不说,你应该使用最适合你需要的。有时候使用xpath和有时候使用linq没有问题。它实际上取决于您的舒适性水平以及可伸缩性和可读性。可以说,什么对团队有利。

        5
  •  0
  •   David    15 年前

    一个xmlReader将比一个xmlDocument使用更少的内存,因为它不需要一次将整个XML加载到内存中。

        6
  •  0
  •   kim3er    15 年前

    只是一个关于jmarsch评论的想法。即使您的流程没有讨论XML生成,您是否考虑将DB(或XML文件的一个子集作为索引)作为中介?这显然只有在XML文件一天不更新一次或两次的情况下才有好处。我想这需要与您现有的缓存机制进行权衡。

    我不能说speed,但是由于语法的原因,我更喜欢xdocument/linq。

    丰富的