我正在尝试反序列化一些我不负责生成的XML。它有一个单片节点和多个模块的各种分支。问题是每个模块可能有相似的子节点,这些子节点具有不同的节点和属性,但共享相同的名称。这些类似的节点没有名称空间。抽象地说,它看起来像这样的目标类型。
<Root>
<Module1>
<Node SomeAttribute="123" />
</Module1>
<Module2>
<Node SomeOtherAttribute="Something" />
</Module2>
</root>
当我尝试使用同时具有Module1
和Module2
作为成员的Root
类型来构造XmlSerializer
时,我似乎有各种建议用命名空间来注释我的pocos,以避免由此产生的异常。
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类结构决定的,而不是我的反序列化节点的名称。
有没有一种方法可以用它的单片形式反序列化这个对象,也许可以用decorator注释Module1.Node
和Module1.Node
poco类?
当我尝试的时候,我找不到相关的装饰师。我确实成功地阻止了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序列化
我不喜欢具体类型的公共方法,但我很难使用ISerializable接口实现私有化和反序列化。
可能还会去看看另一个Serializer,看看进展如何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);
}
}
}
https://dotnetfiddle.net/3AYdVT
只要使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);
}
}
}