【问题标题】:Iteration through XML?通过 XML 迭代?
【发布时间】:2014-06-23 13:21:53
【问题描述】:

我有一个 6GB 的 XML 文件,我正在使用 XmlReader 循环浏览该文件。文件很大,但我对此无能为力。我使用 LINQ,但大小不允许我使用 XDocument,因为我收到 OutOfMemory 错误。

我正在使用 XmlReader 循环遍历整个文件并提取我需要的内容。我包含了一个示例 XML 文件。

基本上,这就是我所做的:

  1. 找到标签容器。如果找到,则检索属性“ID”。
  2. 如果“ID”以 LOCAL 开头,那么这就是我要阅读的内容。
  3. 阅读器循环,直到我找到标签 Family 的值为 CELL_FD
  4. 找到后,循环 reader.read() 直到找到标签 IMPORTANT_VALUE
  5. 找到后,读取 IMPORTANT_VALUE 的值。
  6. 我已经完成了这个 容器,所以继续循环,直到找到下一个 Container(这就是中断的地方)。

这是我阅读文件并找到相关值的简化版本。

while (myReader.Read())
{
    if ((myReader.Name == "CONTAINER"))
    {
        if (myReader.HasAttributes) 
        {
            string Attribute = myReader.GetAttribute("id");
            if (Attribute.IndexOf("LOCAL_") >= 0)
            {
                while (myReader.Read())
                {
                    if (myReader.Name == "FAMILY")
                    {
                        myReader.Read();//read value
                        string Family = myReader.Value;
                        if (Family == "CELL_FDD")
                        {
                            while (myReader.Read())
                            {
                                if ((myReader.Name == "IMPORTANT_VALUE"))
                                {
                                    myReader.Read();
                                    string Counter = myReader.Value;
                                    Console.WriteLine(Attribute + " (found: " + Counter + ")");
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

这是 XML:

<es:esFD xmlns:es="File.xsd">
    <vs:vsFD xmlns:vs="OTHER_FILE.xsd">
    <CONTAINER id="LOCAL_CONTAINER1">
        <ATTRIBUTES>
            <FAMILY>CELL_FDD</FAMILY>
            <CELL_FDD>
                <VAL1>1.1.2.3</VAL1>
                <VAL2>JSMITH</VAL2>
                <VAL3>320</VAL3>
                <IMPORTANT_VALUE>VERY</IMPORTANT_VALUE>
                <VAL4>320</VAL4>
            </CELL_FDD>
            <FAMILY>BLAH</FAMILY>
            <BLAH>
                <VAL1>1.4.43.3</VAL1>
                <VAL2>NA</VAL2>
                <VAL3>349</VAL3>
                <IMPORTANT_VALUE>NA</IMPORTANT_VALUE>
                <VAL4>43</VAL4>
                <VAL5>00</VAL5>
                <VAL6>12</VAL6>
            </BLAH>
        </ATTRIBUTES>
    </CONTAINER>    
    <CONTAINER id="FOREIGN_ELEMENT1">
        <ATTRIBUTES>
            <FAMILY>CELL_FDD</FAMILY>
            <CELL_FDD>
                <VAL1>1.1.2.3</VAL1>
                <VAL2>JSMITH</VAL2>
                <VAL3>320</VAL3>
                <IMPORTANT_VALUE>VERY</IMPORTANT_VALUE>
                <VAL4>320</VAL4>
            </CELL_FDD>
            <FAMILY>BLAH</FAMILY>
            <BLAH>
                <VAL1>1.4.43.3</VAL1>
                <VAL2>NA</VAL2>
                <VAL3>349</VAL3>
                <IMPORTANT_VALUE>NA</IMPORTANT_VALUE>
                <VAL4>43</VAL4>
                <VAL5>00</VAL5>
                <VAL6>12</VAL6>
            </BLAH>
        </ATTRIBUTES>
    </CONTAINER>    
    </vs:vsFD>
</es:esFD>

我怎样才能从最内层的循环中跳出来,以便到达最顶层的循环?

【问题讨论】:

  • 您希望break 将您返回到正在寻找 CONTAINER 元素的循环吗?
  • 我编辑了这个问题,但是是的,我想跳到最顶层的循环。或者只是继续阅读下一个 CONTAINER,因为我不会从当前 CONTAINER 中阅读任何其他内容。
  • 您可以使用 XElement.Load(myReader.ReadSubtree()) 之类的东西将 LINQ to XML 与 XmlReader 结合起来。
  • 我最终使用了@svick 的建议。我该如何结束这个问题?
  • @user3605366 您可以发布您的代码作为答案,然后接受。

标签: c# xml linq-to-xml xmlreader


【解决方案1】:

使用单独的方法应该更容易控制你的循环:

while (myReader.Read())
{
    if ((myReader.Name == "CONTAINER"))
    {
        ProcessContainerElement(myReader);
    }
}

ProcessContainerElement方法中,当你确定需要开始寻找下一个CONTAINER元素时,可以return

private void ProcessContainerElement(XmlReader myReader)
{
    while (whatever)
    {
        if ((myReader.Name == "IMPORTANT_VALUE"))
        {
            myReader.Read();
            string Counter = myReader.Value;
            Console.WriteLine(Attribute + " (found: " + Counter + ")");
            return;
        }
    }
}

【讨论】:

    【解决方案2】:

    您可以使用 XmlReader 读取并将每个节点放入 XmlDocument。

    类似的东西,未经测试:

    bool notFound = false;
    notFound |= !reader.ReadToDescendant("root");
    notFound |= !reader.ReadToDescendant("CONTAINER");
    
    if (notFound)
        Throw new Exception("[Не удаётся найти \"/root/CONTAINER\"]");
    
    do
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(reader.ReadOuterXml());
        XmlNode container = doc.DocumentElement;
    
        // do your work with container
    }
    while (reader.ReadToNextSibling("CONTAINER"));
    
    reader.Close();
    

    【讨论】:

      【解决方案3】:

      使用 svick 的评论,我最终将 LINQ 与 XML 结合起来。到达正确的元素并检查属性是否具有正确的 ID 后,我将其转储到 XElement.Load。

      【讨论】:

      • 考虑在此处添加一些代码来说明您的观点,并尝试更好地解释您的答案。这样,它可以帮助与您有类似问题的未来读者。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-23
      • 2011-03-19
      • 2010-10-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多