使用 System.XML 反序列化无效的 XML
Deserializing Invalid XML with System.XML
我正在尝试反序列化一些我不负责生成的 XML。它有一个整体节点和多个模块的各种分支。问题是每个模块可能有相似的子节点,这些子节点具有不同的节点和属性但共享相同的名称。这些类似的节点没有命名空间。抽象地说,它看起来像这样作为目标类型。
<Root>
<Module1>
<Node SomeAttribute="123" />
</Module1>
<Module2>
<Node SomeOtherAttribute="Something" />
</Module2>
</root>
我似乎有各种建议用命名空间注释我的 pocos,以避免在我尝试使用同时具有 Module1
和 Root
类型构造 XmlSerializer
时出现异常Module2
作为成员。
System.InvalidOperationException : Types 'Root.Module1.Item1' and 'Root.Module1.Item2' both use the XML type name, 'Item', from namespace ''. Use XML attributes to specify a unique XML name and/or namespace for the type.
我认为如果使用 System.Text.Json
我不会有这个问题,因为类型是由 poco class 结构决定的,而不是我正在反序列化的节点的名称。
有没有办法以整体形式反序列化此对象,也许可以通过使用装饰器注释 Module1.Node
和 Module1.Node
poco class?
我试了没找到相关的装饰器。我确实成功地停止了 XmlSerializer
构造函数异常,但它停止识别 Node
类型并且无法反序列化。
我的下一步是为每个模块制作单独的 XmlSerializer
实例,并尝试看看我是否可以取消感觉效率低下的 Root
对象。
这是 fiddle 中的设置示例:
https://dotnetfiddle.net/0twN0O
我有一个解决方案给你,但只有当你在使用它之前修复你的 XML 时它才会起作用(例如 123 应该与“123”一起使用)。
public class Node
{
[XmlAttribute]
public string SomeOtherAttribute { get; set; }
[XmlAttribute]
public int SomeAttribute { get; set; }
}
public class Module
{
public Node Node { get; set; }
}
[XmlRoot("Root")]
public class OrderedItem
{
[XmlElement("Module1")]
public Module Module1 { get; set; }
[XmlElement("Module2")]
public Module Module2 { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
string xml = @"<Root>
<Module1>
<Node SomeAttribute = ""123"" />
</Module1>
<Module2>
<Node SomeOtherAttribute = ""Something"" />
</Module2 >
</Root>";
XmlSerializer serializer = new XmlSerializer(typeof(OrderedItem));
using (TextReader reader = new StringReader(xml))
{
var result = (OrderedItem)serializer.Deserialize(reader);
}
}
}
这是对 @d-a 的回答的一个小扩展,它使用接口来帮助将对象与消费者的观点分开。
以下问题的答案非常有用:
XML serialization of interface property
我不喜欢具体类型的 public 方法,但我努力使用 ISerializable 接口进行私有化和反序列化。
可能仍然会尝试使用另一个 Serialiser 来查看它的运行情况 https://github.com/ExtendedXmlSerializer/home。
using System.IO;
using System.Xml;
using System.Xml.Serialization;
[XmlType]
public class Node : Module1.Node1, Module2.Node2
{
[XmlAttribute]
public string SomeOtherAttribute { get; set; }
[XmlAttribute]
public int SomeAttribute { get; set; }
}
public class Module1
{ [XmlElement(ElementName="Node")]
public Node _node { get; set; }
[XmlIgnore]
public Node1 Node { get {return (Node1)_node ;} }
public interface Node1 {
public int SomeAttribute { get; set; }
}
}
public class Module2
{ [XmlElement(ElementName="Node")]
public Node _node { get; set; }
[XmlIgnore]
public Node2 Node { get {return (Node2)_node ;} }
public interface Node2 {
public string SomeOtherAttribute { get; set; }
}
}
[XmlRoot("Root")]
public class OrderedItem
{
[XmlElement("Module1")]
public Module1 Module1 { get; set; }
[XmlElement("Module2")]
public Module2 Module2 { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
string xml = @"<Root>
<Module1>
<Node SomeAttribute = ""123"" />
</Module1>
<Module2>
<Node SomeOtherAttribute = ""Something"" />
</Module2 >
</Root>";
XmlSerializer serializer = new XmlSerializer(typeof(OrderedItem));
using (TextReader reader = new StringReader(xml))
{
var result = (OrderedItem)serializer.Deserialize(reader);
System.Console.Out.WriteLine(result.Module1.Node.SomeAttribute);
System.Console.Out.WriteLine(result.Module2.Node.SomeOtherAttribute);
}
}
}
只要您使 poco 类 名称唯一即可。 属性 名称无需唯一。因此,Node的类型应该是唯一的,但这种唯一类型的成员可能都称为Node。
https://dotnetfiddle.net/0twN0O
using System.IO;
using System.Xml;
using System.Xml.Serialization;
public class Module1{
public Node1 Node { get; set; }
public class Node1 {
[XmlAttribute]
public int SomeAttribute { get; set; }
}
}
public class Module2
{
public Node2 Node { get; set; }
public class Node2 {
[XmlAttribute]
public string SomeOtherAttribute { get; set; }
}
}
[XmlRoot("Root")]
public class OrderedItem
{
[XmlElement("Module1")]
public Module1 Module1 { get; set; }
[XmlElement("Module2")]
public Module2 Module2 { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
string xml = @"<Root>
<Module1>
<Node SomeAttribute = ""1232"" />
</Module1>
<Module2>
<Node SomeOtherAttribute = ""Something"" />
</Module2 >
</Root>";
XmlSerializer serializer = new XmlSerializer(typeof(OrderedItem));
using (TextReader reader = new StringReader(xml))
{
var result = (OrderedItem)serializer.Deserialize(reader);
System.Console.Out.WriteLine(result.Module1.Node.SomeAttribute);
System.Console.Out.WriteLine(result.Module2.Node.SomeOtherAttribute);
}
}
}
我正在尝试反序列化一些我不负责生成的 XML。它有一个整体节点和多个模块的各种分支。问题是每个模块可能有相似的子节点,这些子节点具有不同的节点和属性但共享相同的名称。这些类似的节点没有命名空间。抽象地说,它看起来像这样作为目标类型。
<Root>
<Module1>
<Node SomeAttribute="123" />
</Module1>
<Module2>
<Node SomeOtherAttribute="Something" />
</Module2>
</root>
我似乎有各种建议用命名空间注释我的 pocos,以避免在我尝试使用同时具有 Module1
和 Root
类型构造 XmlSerializer
时出现异常Module2
作为成员。
System.InvalidOperationException : Types 'Root.Module1.Item1' and 'Root.Module1.Item2' both use the XML type name, 'Item', from namespace ''. Use XML attributes to specify a unique XML name and/or namespace for the type.
我认为如果使用 System.Text.Json
我不会有这个问题,因为类型是由 poco class 结构决定的,而不是我正在反序列化的节点的名称。
有没有办法以整体形式反序列化此对象,也许可以通过使用装饰器注释 Module1.Node
和 Module1.Node
poco class?
我试了没找到相关的装饰器。我确实成功地停止了 XmlSerializer
构造函数异常,但它停止识别 Node
类型并且无法反序列化。
我的下一步是为每个模块制作单独的 XmlSerializer
实例,并尝试看看我是否可以取消感觉效率低下的 Root
对象。
这是 fiddle 中的设置示例: https://dotnetfiddle.net/0twN0O
我有一个解决方案给你,但只有当你在使用它之前修复你的 XML 时它才会起作用(例如 123 应该与“123”一起使用)。
public class Node
{
[XmlAttribute]
public string SomeOtherAttribute { get; set; }
[XmlAttribute]
public int SomeAttribute { get; set; }
}
public class Module
{
public Node Node { get; set; }
}
[XmlRoot("Root")]
public class OrderedItem
{
[XmlElement("Module1")]
public Module Module1 { get; set; }
[XmlElement("Module2")]
public Module Module2 { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
string xml = @"<Root>
<Module1>
<Node SomeAttribute = ""123"" />
</Module1>
<Module2>
<Node SomeOtherAttribute = ""Something"" />
</Module2 >
</Root>";
XmlSerializer serializer = new XmlSerializer(typeof(OrderedItem));
using (TextReader reader = new StringReader(xml))
{
var result = (OrderedItem)serializer.Deserialize(reader);
}
}
}
这是对 @d-a 的回答的一个小扩展,它使用接口来帮助将对象与消费者的观点分开。
以下问题的答案非常有用: XML serialization of interface property
我不喜欢具体类型的 public 方法,但我努力使用 ISerializable 接口进行私有化和反序列化。
可能仍然会尝试使用另一个 Serialiser 来查看它的运行情况 https://github.com/ExtendedXmlSerializer/home。
using System.IO;
using System.Xml;
using System.Xml.Serialization;
[XmlType]
public class Node : Module1.Node1, Module2.Node2
{
[XmlAttribute]
public string SomeOtherAttribute { get; set; }
[XmlAttribute]
public int SomeAttribute { get; set; }
}
public class Module1
{ [XmlElement(ElementName="Node")]
public Node _node { get; set; }
[XmlIgnore]
public Node1 Node { get {return (Node1)_node ;} }
public interface Node1 {
public int SomeAttribute { get; set; }
}
}
public class Module2
{ [XmlElement(ElementName="Node")]
public Node _node { get; set; }
[XmlIgnore]
public Node2 Node { get {return (Node2)_node ;} }
public interface Node2 {
public string SomeOtherAttribute { get; set; }
}
}
[XmlRoot("Root")]
public class OrderedItem
{
[XmlElement("Module1")]
public Module1 Module1 { get; set; }
[XmlElement("Module2")]
public Module2 Module2 { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
string xml = @"<Root>
<Module1>
<Node SomeAttribute = ""123"" />
</Module1>
<Module2>
<Node SomeOtherAttribute = ""Something"" />
</Module2 >
</Root>";
XmlSerializer serializer = new XmlSerializer(typeof(OrderedItem));
using (TextReader reader = new StringReader(xml))
{
var result = (OrderedItem)serializer.Deserialize(reader);
System.Console.Out.WriteLine(result.Module1.Node.SomeAttribute);
System.Console.Out.WriteLine(result.Module2.Node.SomeOtherAttribute);
}
}
}
只要您使 poco 类 名称唯一即可。 属性 名称无需唯一。因此,Node的类型应该是唯一的,但这种唯一类型的成员可能都称为Node。
https://dotnetfiddle.net/0twN0O
using System.IO;
using System.Xml;
using System.Xml.Serialization;
public class Module1{
public Node1 Node { get; set; }
public class Node1 {
[XmlAttribute]
public int SomeAttribute { get; set; }
}
}
public class Module2
{
public Node2 Node { get; set; }
public class Node2 {
[XmlAttribute]
public string SomeOtherAttribute { get; set; }
}
}
[XmlRoot("Root")]
public class OrderedItem
{
[XmlElement("Module1")]
public Module1 Module1 { get; set; }
[XmlElement("Module2")]
public Module2 Module2 { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
string xml = @"<Root>
<Module1>
<Node SomeAttribute = ""1232"" />
</Module1>
<Module2>
<Node SomeOtherAttribute = ""Something"" />
</Module2 >
</Root>";
XmlSerializer serializer = new XmlSerializer(typeof(OrderedItem));
using (TextReader reader = new StringReader(xml))
{
var result = (OrderedItem)serializer.Deserialize(reader);
System.Console.Out.WriteLine(result.Module1.Node.SomeAttribute);
System.Console.Out.WriteLine(result.Module2.Node.SomeOtherAttribute);
}
}
}