【问题标题】:Convert from HUGE Xml to Json从 HUGE Xml 转换为 Json
【发布时间】:2019-07-16 07:11:15
【问题描述】:

我需要帮助将大型 Xml 转换为 Json 格式。

我一直在研究这个话题。我发现了这个:

How to convert JSON to XML or XML to JSON?

Reading large XML documents in .net

Reading and manpulating large xml of 1 GB

嗯,简单的方法是这样的:

XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);

但我无法使用它,因为我的文件很大 (2GB) 所以我得到了OutOfMemoryException

所以,我需要另一种方式来读取大文件。我一直用这种方式:

    using (XmlReader xr = XmlReader.Create(inputPath))
    {
            while (xr.Read())
            {
                 switch(xr.NodeType)
                 {
                     case XmlNodeType.Element:
                       //Do things
                       break;
                     case XmlNodeType.Text:
                       //Do things
                       break;
                     case XmlNodeType.EndElement:
                       //Do things
                       break;
                 }
            }
     }

我读取了 xml 文件并将 xml 转换为 json 并逐个标记连接字符串。但它很复杂,效率极低,而且不能正常工作。

当我研究时,我发现了 LINQ to XML。但我不知道如何使用它。我认为有利于操作和过滤巨大的 xml,但我需要阅读整个文件。

我的 Xml 文件如下所示:

<?xml version="1.0" encoding="utf-8"?>
<root>
   <key>
      <item> value </value>
      <item> value2 </value>
      <item> value3 </value>
   </key>

   <id>1</id>
   <name>Foo</name>

   <hugeArray> //This array has around 12 millions of entries. Here is my problem.
     <item>
        <direction> </direction>
        <companyId> </companyId>
        <nameId> </nameId>
     </item>
     <item>
        <direction> </direction>
        <companyId> </companyId>
        <nameId> </nameId>
     </item>
      ....
   </hugeArray>
</root>

我发现数组有问题。我不知道如何剪切和阅读它。

我应该如何阅读整个文件? json应该怎么写?

我正在连接字符,但我可以使用 JsonWriter 类。

更新:

该算法应该能够从任何xml转换为json。

【问题讨论】:

  • @JohnB 但我将它与XmlReader一起使用
  • 您是否尝试过 Load 而不是 LoadXml docs.microsoft.com/en-us/dotnet/api/…?我猜应该分部分流式传输而不是一次全部加载。
  • @Slai 是的。它开始阅读,但在 5 分钟后我收到 OutOfMemoryException

标签: c# json xml


【解决方案1】:

尝试推荐的 Microsoft 技术: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/how-to-perform-streaming-transform-of-large-xml-documents

因此,例如,您有以下部分代码:

                while (reader.Read())  
                {  
                    if (reader.NodeType == XmlNodeType.EndElement)  
                        break;  
                    if (reader.NodeType == XmlNodeType.Element  
                        && reader.Name == "Item")  
                    {  
                        item = XElement.ReadFrom(reader) as XElement;  
                        if (item != null)  
                        {  
                            //here you can get data from your array object
                            //and put it to your JSON stream
                        }  
                    }  
                } 

如果你想定义元素的类型,你可以检查它是否有子元素: How to check if XElement has any child nodes?

它应该与 JSON 流配合使用。有关 JSON 蒸汽的更多信息,请查看:Writing JSON to a stream without buffering the string in memory

【讨论】:

  • 我在研究中看到了这个链接,但是......我找不到这样做的方法。我认为这种技术适用于过滤数据,但我需要整个文件。
  • 已编辑。请检查 JSON 流的第二部分。在那里你可以找到一个编写解析数组和对象的例子。
  • 我可以像示例一样使用JsonWriter,但首先,我需要读取整个文件,并且我认为流式转换用于过滤数据。我不知道如何阅读所有内容。
  • 可能没有办法读取整个文件而不将其放入内存,然后才遍历节点并将它们转换为 JSON。您应该从 XML 流中读取节点并将转换后的节点放入 JSON,然后读取一组新的流,转换,放入 JSON。以此类推,直到文件结束。
  • 是的,你是对的。但是我应该如何阅读它?我的意思是,我有一个包含 1200 万个条目的数组。你如何在那里使用LINQ?我无法过滤数据。我可以使用 LINQ 来按部分读取吗?
【解决方案2】:

大文件总是需要使用 XmlReader。我在下面的代码中使用了 XmlReader 和 Xml Linq 的组合

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication120
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            List<Dictionary<string, string>> items = new List<Dictionary<string, string>>();
            XmlReader reader = XmlReader.Create(FILENAME);

            reader.ReadToFollowing("hugeArray");

            while (!reader.EOF)
            {
                if (reader.Name != "item")
                {
                    reader.ReadToFollowing("item");
                }
                if (!reader.EOF)
                {
                    XElement item = (XElement)XElement.ReadFrom(reader);
                    Dictionary<string, string> dict = item.Elements()
                        .GroupBy(x => x.Name.LocalName, y => (string)y)
                        .ToDictionary(x => x.Key, y => y.FirstOrDefault());

                    items.Add(dict);
                }
            }
        }
    }


}

【讨论】:

  • 感谢您回答我。这儿存在一个问题。该算法应该能够读取任何 XML。所以,我不能使用数据模型。
  • XElement 项可以使用匿名方法读取,或者您可以使类 Item 接受泛型类型
  • 你能告诉我一个匿名的方法吗?有点sn-p?
  • 我更新了代码以使用字典使其更通用。
猜你喜欢
  • 1970-01-01
  • 2018-08-30
  • 1970-01-01
  • 2013-05-09
  • 1970-01-01
  • 2013-11-25
  • 2013-09-01
  • 1970-01-01
相关资源
最近更新 更多