0

我正在尝试反序列化一些我不负责生成的 XML。它有一个单一的节点和几个模块的各种分支。问题是每个模块可能具有相似的子节点,这些子节点具有不同的节点和属性,但名称相同。这些相似的节点没有命名空间。在抽象中,它看起来像这样作为目标类型。

<Root>
    <Module1>
         <Node SomeAttribute="123" />
    </Module1>
    <Module2>
         <Node SomeOtherAttribute="Something" />
    </Module2>
</root>

我似乎有各种建议来用命名空间注释我的 pocos 以避免在我尝试XmlSerializer使用同时具有和作为成员的Root类型构造一个时产生的异常。Module1Module2

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 类结构决定的,而不是我被反序列化的节点的名称。

有没有办法以整体形式反序列化这个对象,也许是通过用装饰器注释Module1.Node和poco 类?Module1.Node

我尝试时找不到相关的装饰器。我确实成功地停止了XmlSerializer构造函数异常,但它停止识别Node类型并且也无法反序列化。

我的下一步将为XmlSerializer每个模块创建单独的实例,并尝试看看我是否可以取消Root无论如何感觉效率低下的对象。

这是小提琴中的设置示例: https ://dotnetfiddle.net/0twN0O

4

3 回答 3

1

我为您提供了一个解决方案,但只有在您在使用 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);
        }

    }
}
于 2022-03-02T09:00:04.077 回答
0

这是@da 的答案的一个小扩展,它使用接口来帮助将对象与消费者的观点分开。

以下问题的答案非常有用: 接口属性的 XML 序列化

我不喜欢具体类型的公共方法,但我努力使用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);
        }

    }
}

https://dotnetfiddle.net/3AYdVT

于 2022-03-02T13:58:31.823 回答
0

只要您使 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);
        }

    }
}
于 2022-03-02T14:17:05.070 回答