2017-06-20 30 views
1

我面临的问题与.net XmlSerializer,基本上我需要一个或多个具有相同名称的元素在固定架构的其他元素之间动态地序列化(和反序列化)。XmlSerialization与XmlAnyElement到XmlNode和Order属性

例子:

<?xml version="1.0" encoding="utf-8"?> 
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <asd>asd</asd> 
    <nnn>q</nnn> 
    <nnn>w</nnn> 
    <nnn>e</nnn> 
    <aaa>aaa</aaa> 
</A> 

我真正<nnn>标签是多一点点复杂,里面(不只是条件表达式)动态标签,但我目前threating这一权利。 我真的需要使用的XmlElement“订单”参数来控制的一些规则。

我不能改变的XML布局。

的示例序列化的类:

[XmlRoot] 
[Serializable] 
public class A 
{ 
    [XmlElement("asd", Order=1)] 
    public string asd { get; set; } 

    [XmlIgnore] 
    public string[] qwe { get; set; } 

    [XmlAnyElement("nnn", Order=2)] 
    public XmlNode[] nnn 
    { 
     get 
     { 
      if (qwe == null) return null; 

      var xml = new XmlDocument(); 
      var nodes = new List<XmlNode>(qwe.Length); 

      foreach (var q in qwe) 
      { 
       var nnnTag = xml.CreateNode(XmlNodeType.Element, "nnn", null); 
       nnnTag.InnerText = q; 
       nodes.Add(nnnTag); 
      } 

      return nodes.ToArray(); 
     } 
     set 
     { 
      if (value == null) return; 
      qwe = value.Select(tag => tag.InnerText).ToArray(); 
     } 
    } 

    [XmlElement("aaa", Order=3)] 
    public string aaa { get; set; } 

的问题是,不使用时,“订单”参数序列化变为正常,但与该参数的XmlAnyElement后的元件被理解为在阵列的一部分节点等都不是反序列化的权利。

我对一例的主要程序是,具有下列主要控制台应用程序:

static void Main(string[] args) 
{ 
    var a = new A 
    { 
     aaa = "aaa", 
     asd = "asd", 
     qwe = new[] {"q", "w", "e"} 
    }; 
    var s = Serialize(a); 
    var ss = Deserialize<A>(s); 
    var s2 = Serialize(ss); 

    Console.WriteLine(s); 
    Console.WriteLine(s2); 

    Console.WriteLine("Equals: {0};", s == s2); 

    Console.ReadKey(); 
} 

错误的输出是:

<?xml version="1.0" encoding="utf-8"?> 
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <asd>asd</asd> 
    <nnn>q</nnn> 
    <nnn>w</nnn> 
    <nnn>e</nnn> 
    <aaa>aaa</aaa> 
</A> 
<?xml version="1.0" encoding="utf-8"?> 
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <asd>asd</asd> 
    <nnn>q</nnn> 
    <nnn>w</nnn> 
    <nnn>e</nnn> 
    <nnn>aaa</nnn> 
</A> 
Equals: False; 

为了进行测试,这里是序列化/反序列化片段我使用:

public static string Serialize<T>(T a) 
{ 
    var s = new XmlSerializer(typeof(T)); 
    using (var ms = new MemoryStream()) 
    { 
     using (TextWriter sw = new StreamWriter(ms)) 
     { 
      s.Serialize(sw, a); 
      ms.Seek(0, 0); 
      using (var sr = new StreamReader(ms)) 
      { 
       return sr.ReadToEnd(); 
      } 
     } 
    } 
} 

public static T Deserialize<T>(string a) 
{ 
    var s = new XmlSerializer(typeof(T)); 
    var bytes = Encoding.ASCII.GetBytes(a); 
    using (var ms = new MemoryStream(bytes)) 
    { 
     return (T) s.Deserialize(ms); 
    } 
} 

完整的源代码: https://gist.github.com/inventti-gabriel/81054269f2e0a32d7e8d1dd44f30a97f

在此先感谢。代替XmlAnyElement作为节点使用XmlArrayAttribute

+2

这看起来像我的错误。你能给出更多的具体细节,究竟是什么'nnn'?因为您可以[更改为此](https://dotnetfiddle.net/E2b4xp)作为示例,但这可能不适用于您的“真实”情况。顺便说一句,在这个例子中你可以简化你的serialize/deserialize方法来使用'StringWriter' /'StringReader'。 –

回答

1

我@CharlesMager同意这确实出现了一个错误XmlSerializer

话虽这么说,你可以解决的bug通过引入一个中间的包装类或结构包含任意节点,然后修改您的代理nnn财产与[XmlElement("nnn", Order = 2)]标志着财产后返回这些结构的数组:

[XmlRoot] 
[Serializable] 
public class A 
{ 
    [XmlElement("asd", Order = 1)] 
    public string asd { get; set; } 

    [XmlIgnore] 
    public string[] qwe { get; set; } 

    [XmlElement("nnn", Order = 2)] 
    public XmlNodeWrapper [] nnn 
    { 
     get 
     { 
      if (qwe == null) 
       return null; 

      var xml = new XmlDocument(); 
      var nodes = new List<XmlNode>(qwe.Length); 

      foreach (var q in qwe) 
      { 
       var nnnTag = xml.CreateNode(XmlNodeType.Element, "nnn", null); 
       nnnTag.InnerText = q; 
       nodes.Add(nnnTag); 
      } 

      return nodes.Select(n => (XmlNodeWrapper)n.ChildNodes).ToArray(); 
     } 
     set 
     { 
      if (value == null) 
       return; 
      qwe = value.Select(tag => tag.InnerText()).ToArray(); 
     } 
    } 

    [XmlElement("aaa", Order = 3)] 
    public string aaa { get; set; } 
} 

[XmlType(AnonymousType = true)] 
public struct XmlNodeWrapper 
{ 
    public static implicit operator XmlNodeWrapper(XmlNodeList nodes) 
    { 
     return new XmlNodeWrapper { Nodes = nodes == null ? null : nodes.Cast<XmlNode>().ToArray() }; 
    } 

    public static implicit operator XmlNode[](XmlNodeWrapper wrapper) 
    { 
     return wrapper.Nodes; 
    } 

    // Marking the Nodes property with both [XmlAnyElement] and [XmlText] indicates that the node array 
    // may contain mixed content (I.e. both XmlElement and XmlText objects). 
    // Hat tip: https://stackoverflow.com/questions/25995609/xmlserializer-node-containing-text-xml-text 
    [XmlAnyElement] 
    [XmlText] 
    public XmlNode[] Nodes { get; set; } 

    public string InnerText() 
    { 
     if (Nodes == null) 
      return null; 
     return String.Concat(Nodes.Select(n => n.InnerText)); 
    } 
} 

请注意,XmlNodeWrapper中的Nodes属性标有[XmlAnyElement][XmlText]。要求做到这一点解释here

样品fiddle

0

尝试是阵列

+0

我试过了,但是这打破了XML的结构 – gariel