【问题标题】:Recursive XML Deserializes Incorrectly递归 XML 反序列化不正确
【发布时间】:2021-07-16 09:30:55
【问题描述】:

(详情请见this demo

假设我有一个这样的 XML 文件:

<?xml version="1.0" encoding="utf-16"?>
<Container>
  <SomeValue>1</SomeValue>
  <Item>
    <Containers>
      <Container>
        <SomeValue>2</SomeValue>
          <Item>
            <!-- etc... -->
          </Item>
      </Container>
      <Container>
        <SomeValue>3</SomeValue>
      </Container>
    </Containers>
  </Item>
</Container>

其中名为Container 的类包含一个Item,而名为Item 的类可以有许多子容器。

Container 类实现了IXmlSerializable(原因见注释),它有以下方法:

public void ReadXml(XmlReader reader)
{
    XElement root = XElement.Load(reader.ReadSubtree());
    this.SomeValue = (int)root.Element("SomeValue");

    XElement itemElt = root.Element("Item");
    if (itemElt == null)
    {
        // Empty container
        return;
    }

    XmlSerializer xmlSerializer = new XmlSerializer(typeof(Item));
    using (var itemReader = itemElt.CreateReader())
    {
        this.Item = (Item)xmlSerializer.Deserialize(itemReader);
    }
}

但是,即使在其Containers 节点中有多个容器,运行此操作也会导致根容器的项目仅包含第一个容器(其中 SomeValue 为 2)。


那么为什么会跳过其他容器,我该如何解决呢?


我假设这是对 ReadSubtree() 的调用的问题,但忽略它会给我:

InvalidOperationException: The XmlReader state should be EndOfFile after this operation.

一些注意事项:

我必须使用IXmlSerializable 的原因是因为实际的“项目”类型是从数据库中获取的,具体取决于元素的名称。所以当我打电话给new XmlSerializer(typeof(Item))时,我实际上是在打电话给new XmlSerializer(specificItemType)

此外,我更愿意尽可能多地使用System.Xml.Linq,因为它非常易读(而且我对 XML 的东西还很陌生)。它还允许我从树中的任何位置获取数据,而无需重新读取整个文档,我在实际代码中做了一些工作。但是,如果一定要走,我愿意放弃。

【问题讨论】:

    标签: c# xml linq recursion deserialization


    【解决方案1】:

    问题在于:

    XElement root = XElement.Load(reader.ReadSubtree());
    

    将读者留在元素的末尾(即&lt;/Container&gt;)。 IXmlSerializable.ReadXml 的约定是您也必须“阅读”此内容,将阅读者留在下一个元素的开头。 This answer 有助于澄清这一点。

    所以解决方法是在返回之前添加另一个 reader.Read() 调用。我更新了your demo:

    ===Input===
    Container {1} - Item: [ Container {2} - null, Container {3} - null ] (2)
    
    ===Output===
    Container {1} - Item: [ Container {2} - null, Container {3} - null ] (2)
    

    【讨论】:

    • 我不敢相信我错过了。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    相关资源
    最近更新 更多