2012-06-18 24 views
19

私はDataContractSerializerでシリアル化されたデータクラスを持っています。このクラスでは、Namespace宣言のない[DataContract]属性が使用されます。したがって、結果として得られるXMLファイル内の名前空間は、クラスの名前空間に基づいて生成されます。DataContractSerializer - 名前空間を変更し、古い名前空間にバインドされたファイルの逆シリアル化

クラスは基本的に次のようになります。変更することにより、

<?xml version="1.0" encoding="utf-8"?> 
<Data xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/XYZ"> 
    <Prop1>StringValue</Prop1> 
    <Prop2>11</Prop2> 
</Data> 

は今、私はクラスの名前空間を変更したい(実際にはそれを削除):

namespace XYZ 
{ 
    [DataContract] 
    public class Data 
    { 
     [DataMember(Order = 1)] 
     public string Prop1 { get; set; } 

     [DataMember(Order = 2)] 
     public int Prop2 { get; set; } 
    } 
} 

...と結果のXML [DataContract]属性は[DataContract(Namespace = "")]です。しかし、いったんこれを行うと、元の名前空間で以前に直列化されたファイルは、デシリアライズされなくなりました。私は次の例外を受け取る:

Error in line 1 position XXX. Expecting element 'Data' from namespace ''.. Encountered 'Element' with name 'Data', namespace 'http://schemas.datacontract.org/2004/07/XYZ'.

これは完璧な理にかなっています。私は名前空間を変更しました。私はそれで大丈夫です。しかし、DataContractSerializerに名前空間が一致しなくてもそのデータを逆シリアル化するよう指示する必要があるようです。

+0

なぜ、DataContract属性の名前空間に空の文字列を指定したいのですか?あなたは何をしているのですか? –

+2

私はクラスのCLR名前空間に縛られていません。それが本当にここの問題です。このクラスはCLR名前空間を変更しています。その実装の詳細に縛られたくありません。私はもちろん、一定に保つことができるxml名前空間の値を定義することができます。しかし、この実装では、xml名前空間を単に削除するのではなく、その実装の利点がわかりません。これは単純なファイルのシリアライゼーションに使用されています。 – harlam357

答えて

15

可能な方法の1つは、シリアライザで使用されるリーダーを、以下に示すように古い名前空間を新しい名前空間にマップするリーダーにラップすることです。コードはたくさんありますが、ほとんどは自明です。

public class StackOverflow_11092274 
{ 
    const string XML = @"<?xml version=""1.0"" encoding=""utf-8""?> 
<Data xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"" xmlns=""http://schemas.datacontract.org/2004/07/XYZ""> 
    <Prop1>StringValue</Prop1> 
    <Prop2>11</Prop2> 
</Data>"; 

    [DataContract(Name = "Data", Namespace = "")] 
    public class Data 
    { 
     [DataMember(Order = 1)] 
     public string Prop1 { get; set; } 

     [DataMember(Order = 2)] 
     public int Prop2 { get; set; } 
    } 

    public class MyReader : XmlReader 
    { 
     XmlReader inner; 
     public MyReader(XmlReader inner) 
     { 
      this.inner = inner; 
     } 

     public override int AttributeCount 
     { 
      get { return inner.AttributeCount; } 
     } 

     public override string BaseURI 
     { 
      get { return inner.BaseURI; } 
     } 

     public override void Close() 
     { 
      inner.Close(); 
     } 

     public override int Depth 
     { 
      get { return inner.Depth; } 
     } 

     public override bool EOF 
     { 
      get { return inner.EOF; } 
     } 

     public override string GetAttribute(int i) 
     { 
      return inner.GetAttribute(i); 
     } 

     public override string GetAttribute(string name, string namespaceURI) 
     { 
      return inner.GetAttribute(name, namespaceURI); 
     } 

     public override string GetAttribute(string name) 
     { 
      return inner.GetAttribute(name); 
     } 

     public override bool IsEmptyElement 
     { 
      get { return inner.IsEmptyElement; } 
     } 

     public override string LocalName 
     { 
      get { return inner.LocalName; } 
     } 

     public override string LookupNamespace(string prefix) 
     { 
      return inner.LookupNamespace(prefix); 
     } 

     public override bool MoveToAttribute(string name, string ns) 
     { 
      return inner.MoveToAttribute(name, ns); 
     } 

     public override bool MoveToAttribute(string name) 
     { 
      return inner.MoveToAttribute(name); 
     } 

     public override bool MoveToElement() 
     { 
      return inner.MoveToElement(); 
     } 

     public override bool MoveToFirstAttribute() 
     { 
      return inner.MoveToFirstAttribute(); 
     } 

     public override bool MoveToNextAttribute() 
     { 
      return inner.MoveToNextAttribute(); 
     } 

     public override XmlNameTable NameTable 
     { 
      get { return inner.NameTable; } 
     } 

     public override string NamespaceURI 
     { 
      get 
      { 
       if (inner.NamespaceURI == "http://schemas.datacontract.org/2004/07/XYZ") 
       { 
        return ""; 
       } 
       else 
       { 
        return inner.NamespaceURI; 
       } 
      } 
     } 

     public override XmlNodeType NodeType 
     { 
      get { return inner.NodeType; } 
     } 

     public override string Prefix 
     { 
      get { return inner.Prefix; } 
     } 

     public override bool Read() 
     { 
      return inner.Read(); 
     } 

     public override bool ReadAttributeValue() 
     { 
      return inner.ReadAttributeValue(); 
     } 

     public override ReadState ReadState 
     { 
      get { return inner.ReadState; } 
     } 

     public override void ResolveEntity() 
     { 
      inner.ResolveEntity(); 
     } 

     public override string Value 
     { 
      get { return inner.Value; } 
     } 
    } 

    public static void Test() 
    { 
     DataContractSerializer dcs = new DataContractSerializer(typeof(Data)); 
     MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(XML)); 
     try 
     { 
      XmlReader r = XmlReader.Create(ms); 
      XmlReader my = new MyReader(r); 
      Data d = (Data)dcs.ReadObject(my); 
      Console.WriteLine("Data[Prop1={0},Prop2={1}]", d.Prop1, d.Prop2); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e); 
     } 
    } 
} 
+2

これはうまくいった!私は間違ったレベルで問題を攻撃していました。本当にありがとう!少し難しいと判明した 'Dictionary 'インスタンスを含むより複雑なデータ型があります。各KVPのタグが変更されたので、名前空間の変更に基づいて、 ''から ''に変更するものとします。これらのファイルを手動で変換する必要がありましたが、問題ありません。これらのファイル/タイプは、読み取る必要のある少数を表します。 – harlam357

関連する問題