XML错误:存在多个根元素

55

我从 Web 服务获取 XML。以下是 XML 的样式:

<parent>
    <child>
        Text
    </child>
</parent>
<parent>
    <child>
        <grandchild>
            Text
        </grandchild>
        <grandchild>
            Text
        </grandchild>
    </child>
    <child>
        Text
    </child>
</parent>

etc.

这是我的C#代码:
StringBuilder output = new StringBuilder();

// Create an XmlReader
using (XmlReader reader = XmlReader.Create(new StringReader(xoResponse.@return)))
{
    XmlWriterSettings ws = new XmlWriterSettings();
    //ws.Indent = true;
    using (XmlWriter writer = XmlWriter.Create(output, ws))
    {
        // Parse the file and display each of the nodes.
        while (reader.Read())
        {
            switch (reader.NodeType)
            {
                case XmlNodeType.Element:
                    writer.WriteStartElement(reader.Name);
                    break;
                case XmlNodeType.Text:
                    writer.WriteString(reader.Value);
                    break;
                case XmlNodeType.XmlDeclaration:
                case XmlNodeType.ProcessingInstruction:
                    writer.WriteProcessingInstruction(reader.Name, reader.Value);
                    break;
                case XmlNodeType.Comment:
                    writer.WriteComment(reader.Value);
                    break;
                case XmlNodeType.EndElement:
                    writer.WriteFullEndElement();
                    break;
            }
        }
    }
}

我相信错误是在第二个父元素上抛出的。我该如何避免这个错误?非常感谢任何帮助。


4
首先,你从网络服务中获取的那些东西并不是XML,因为它有两个根元素,这就是导致你问题的原因。你是怎么从网络服务中获取它的?你是否无意中去掉了真正的根元素? - Matt Gibson
@Matt - 不,我是直接从网络服务返回响应。 - divided
在这种情况下,我会向服务提供商提到,拥有一个看起来非常像XML但实际上不是XML的文档格式一点也不好玩 :) 我想知道它是否只是损坏了,还是他们故意这样做的一些非常奇怪的原因? - Matt Gibson
2
@Matt - 很好的观点,我会向他们提出。也许这是一个测试,以排除任何不值得信赖的网络服务用户? :) - divided
3
这是“XML”,但它不是一个XML文档。你仍然可以解析它,只需要放松XmlReader的限制。请参见下面的答案。 - Mark Lakata
4个回答

93

你可以在不修改XML流的情况下做到:告诉XmlReader不要那么挑剔。 将XmlReaderSettings.ConformanceLevel设置为ConformanceLevel.Fragment,解析器就会忽略没有根节点的事实。

XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
using (XmlReader reader = XmlReader.Create(tr,settings))
{
    ...
}

现在你可以解析像这样的内容(这是一个实时的XML流,不可能用节点包装起来)。
<event>
  <timeStamp>1354902435238</timeStamp>
  <eventId>7073822</eventId>
</event>
<data>
  <time>1354902435341</time>
  <payload type='80'>7d1300786a0000000bf9458b0518000000000000000000000000000000000c0c030306001b</payload>
</data>
<data>
  <time>1354902435345</time>
  <payload type='80'>fd1260780912ff3028fea5ffc0387d640fa550f40fbdf7afffe001fff8200fff00f0bf0e000042201421100224ff40312300111400004f000000e0c0fbd1e0000f10e0fccc2ff0000f0fe00f00f0eed00f11e10d010021420401</payload>
</data>
<data>
  <time>1354902435347</time>
  <payload type='80'>fd126078ad11fc4015fefdf5b042ff1010223500000000000000003007ff00f20e0f01000e0000dc0f01000f000000000000004f000000f104ff001000210f000013010000c6da000000680ffa807800200000000d00c0f0</payload>
</data>

关于“它不是一个XML文档”的说法:这是一个观点和角度的问题。输入是一系列有效的XML片段。我使用了这个答案。 - H H
这个可行。我必须解析几GB的.svclog文件,但是用一个根标签包装整个内容以获得正确的“XML”不是一个选项。 - Wiizl

61

您需要将<parent>元素封装在一个包围元素中,因为XML文档只能有一个根节点:

<parents> <!-- I've added this tag -->
    <parent>
        <child>
            Text
        </child>
    </parent>
    <parent>
        <child>
            <grandchild>
                Text
            </grandchild>
            <grandchild>
                Text
            </grandchild>
        </child>
        <child>
            Text
        </child>
    </parent>
</parents> <!-- I've added this tag -->

由于您从其他地方接收到此标记而不是自己生成它,因此您可能需要将响应视为字符串并使用适当的标记进行包装,然后再尝试将其解析为XML。

因此,您有几个选择:

  1. 让Web服务提供商返回具有一个根节点的实际XML
  2. 像我上面建议的那样预处理XML以添加根节点
  3. 预处理XML以将其拆分为多个块(即每个<parent>节点一个),并将每个块作为单独的XML文档处理

@Rob 如果每个父元素上都有一个Doctype元素怎么办..考虑一下我的情况,在我的问题中http://stackoverflow.com/questions/7074036/reading-big-chunk-of-xml-data-from-socket-and-parse-on-the-fly,它是Java而不是C#,但我认为逻辑是相同的.. - Krishnabhadra
5
不需要修改XML流就可以完成这个任务,可以参考我下面的回答。 - Mark Lakata
3
最后应该是</parents> - Azimuth

9

将xml包装在另一个元素中

<wrapper>
<parent>
    <child>
        Text
    </child>
</parent>
<parent>
    <child>
        <grandchild>
            Text
        </grandchild>
        <grandchild>
            Text
        </grandchild>
    </child>
    <child>
        Text
    </child>
</parent>
</wrapper>

7

如果您负责(或对Web服务有任何控制权),请让他们添加一个唯一的根元素!

如果您无法更改它,请使用一些正则表达式或字符串分割来解析每个 `
` 并将每个 `
` 元素传递给您的 XML Reader。

或者,您可以手动添加一个垃圾根元素,通过在开头添加前缀标签并在结尾添加后缀标签。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接