【问题标题】:XML deserialisation of inner elements内部元素的 XML 反序列化
【发布时间】:2012-08-03 16:37:26
【问题描述】:

是否可以将内部 xml 元素反序列化为其等效类?我有以下 xml 片段:

<?xml version="1.0" encoding="utf-8" ?>
<tileconfiguration xmlns="http://somenamespace/tile-configuration">
   <tile top_left_x="3" top_left_y="1" bottom_right_x="38" bottom_right_y="48">
     <child>
     </child>
   </tile>
</tileconfiguration>

以及代表&lt;tile /&gt; 元素的等效类:

[System.Xml.Serialization.XmlRoot(ElementName = "tile")]
public class Tile : System.Xml.Serialization.IXmlSerializable
{
    public System.Xml.Schema.XmlSchema GetSchema()
    {
        throw new NotImplementedException();
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        throw new NotImplementedException();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        throw new NotImplementedException();
    }
}

问题是,每次我尝试反序列化 &lt;tile_configuration /&gt; 中的 &lt;tile /&gt; 实例时,XML 反序列化器都会抛出 文档 (2,2) 中的错误

        System.Xml.Serialization.XmlSerializer serial = new System.Xml.Serialization.XmlSerializer(typeof(Tile));
        System.IO.TextReader t = new System.IO.StreamReader("c:\\temp\\deserial.xml");
        Tile q = (Tile)serial.Deserialize(t);

如果我创建一个类来表示 &lt;tile_configuration /&gt; 并直接从中反序列化,它工作正常,调试器进入 TileConfiguration 类的 ReadXml 方法,然后我可以从中管理子 @987654330 的解析@(和后代)元素 - 但这需要每次重新读取整个 xml 文件。

简而言之;我是否需要读取和写入整个 XML 文件 - 每次我想使用序列化/反序列化时从根 xml 元素开始,或者有没有办法让我忽略多余的外部元素并直接将相关的子 xml 元素反序列化到他们的没有解析器卡盘错误的代码等效项?

非常感谢。

【问题讨论】:

    标签: c# .net xml serialization deserialization


    【解决方案1】:

    如果您想忽略外部元素并拥有完全控制权并以低开销快速实现,我建议不要使用XMLSerializer,而是分别使用XmlReaderXmlWriter

    您还可以通过使用XmlReader 来构建中间DOM 并使用XMLSerializer 将DOM 写入输出文件来实现组合方法。

    【讨论】:

      【解决方案2】:

      是的。一种想法是加载 xml 并使用 Xpath 查询选择所需的节点。然后反序列化查询结果所代表的xml。

      【讨论】:

      • 认为这可能类似于限制范围。太棒了,非常感谢,我会试一试。
      • 你有没有得到这个?我也面临同样的问题
      【解决方案3】:

      鉴于您对 XML 的展示,应该没有必要实现 IXmlSerializable。你可以试试这个:

      [XmlRoot("tileconfiguration")]
      public class TileConfiguration
      {
          [XmlElement("tile")]
          public List<Tile> Tiles { get; set; }
      }
      
      [XmlRoot("tile")]
      public class Tile
      {
          [XmlAttribute("top_left_x")]
          public int TopLeftX { get; set; }
      
          [XmlAttribute("top_left_y")]
          public int TopLeftY { get; set; }
      
          [XmlAttribute("bottom_right_x")]
          public int BottomRightX { get; set; }
      
          [XmlAttribute("bottom_right_y")]
          public int BottomRightY { get; set; }
      
          [XmlElement("child")]
          public List<Child> children { get; set; }
      }
      
      [XmlRoot("child")]
      public class Child
      {
      }
      
      XmlSerializer serializer = XmlSerializer(typeof(TileConfiguration));
      TileConfiguration tileConfiguration = (TileConfiguration)serializer.Deserialize(stream);
      

      您还可以使用 XmlReader 来获取所需的元素:

      List<Tile> tiles = new List<Tile>();
      XmlSerializer serializer = XmlSerializer(typeof(Tile));
      
      using (XmlTextReader xr = new XmlTextReader(xmlStream))
      {
          while (!xr.EOF)
          {
              xr.MoveToContent();
              xr.ReadToDescendant("tile");
      
              if (xr.Name == "tile")
              {
                  string tileXml = xr.ReadOuterXml();
                  using (StringReader tileReader = new StringReader(tileXml))
                  {
                      Tile tile = (Tile)serializer.Deserialize(tileReader);
                      tiles.Add(Tile);
                  }
              }
              else
              {
                  xr.ReadEndElement();
              }
          }
      }
      

      【讨论】:

      • 非常感谢!我实现了 ISerializable,因为我给出的示例仅用于说明。在现实世界中,有许多不可序列化的对象嵌套为子对象,并且需要某些定制的序列化操作,而“自动”XMAttribute[] 装饰无法正确处理。
      猜你喜欢
      • 2011-06-24
      • 1970-01-01
      • 1970-01-01
      • 2017-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多