通过XML迭代?

时间:2014-05-06 19:10:16

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

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

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

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

  1. 查找代码容器。如果找到,则检索属性“ID”。
  2. 如果“ID”以 LOCAL 开头,那么这就是我要阅读的内容。
  3. 读取器循环,直到找到值 CELL_FD
  4. 的标签 Family
  5. 找到后,循环阅读器.read(),直到找到标签 IMPORTANT_VALUE
  6. 找到后,读取 IMPORTANT_VALUE 的值。
  7. 我已经完成了容器,所以继续循环直到找到下一个容器(这就是中断的地方)。
  8. 这是我阅读文件和查找相关值的简化版本。

    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>
    

    如何摆脱最内圈,以便能够达到最顶层的循环?

3 个答案:

答案 0 :(得分:4)

使用单独的方法可以更容易地控制循环:

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;
        }
    }
}

答案 1 :(得分:1)

您可以使用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();

答案 2 :(得分:-1)

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

相关问题