2017-06-20 1 views
1

私はXmlSerializerの問題に直面していますが、基本的に固定スキーマの他の要素間で同じ名前の1つ以上の要素を動的にシリアライズ(およびデシリアライズ)する必要があります。XmlSerializationで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>タグは(だけでなく、条件文)内のダイナミックタグで、もう少し複雑ですが、私は現在、この権利を脅威としています。 私は本当にいくつかのルールを制御するためにXmlElementの "注文"パラメータを使用する必要があります。

私はXMLレイアウトを変更できません。

例直列化可能クラス:XmlAnyElementはのアレイの一部として理解された後

[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; } 

問題は、「注文」パラメータを使用していないシリアル化がうまく行くとき、ですが、パラメータを持つ要素ノードとそれは右にdeserializedされていません。例えば

私の主なプログラムは以下の主要なとコンソールアプリケーションです:間違った出力がある

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

ありがとうございます。

+2

これは私のバグのようです。あなたは 'nnn'が実際に何をしているのか、もっと具体的に言えますか?この例では[これに変更する](https://dotnetfiddle.net/E2b4xp)することができますが、実際の場合は正しく動作しない可能性があります。この例では、 'StringWriter' /' StringReader'を使用するためにserialize/deserializeメソッドを単純化することができます。 –

答えて

1

ている私は、これはXmlSerializerのバグのように見えるん@CharlesMagerに同意ノードとしてXmlAnyElementの代わりにXmlArrayAttributeを使用してみてください。言われて、あなたは[XmlElement("nnn", Order = 2)]でプロパティをマークした後、これらの構造体の配列を返すために、あなたの代理nnnプロパティを変更し、その後、任意のノードを含むように、中間ラッパークラスまたは構造体を導入することによって、バグを回避できることを

[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)); 
    } 
} 

XmlNodeWrapperNodesプロパティは、[XmlAnyElement][XmlText]の両方でマークされています。これを行うための要件は、hereで説明されています。

サンプルfiddle

0

は、アレイ

+0

私は試みましたが、これはXMLの構造を破壊します – gariel

関連する問題