2012-06-18 33 views
19

Ho una classe di dati che è serializzata con DataContractSerializer. La classe utilizza l'attributo [DataContract] senza esplicita dichiarazione Namespace. In quanto tale, lo spazio dei nomi nel file xml risultante viene generato in base allo spazio dei nomi della classe.DataContractSerializer - modifica lo spazio dei nomi e deserializza il file associato allo spazio dei nomi precedente

La classe si presenta sostanzialmente in questo modo:

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

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

... e l'XML risultante:

<?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> 

Ora voglio cambiare lo spazio dei nomi della classe (in realtà elimina) cambiando l'attributo [DataContract] a [DataContract(Namespace = "")]. Tuttavia, una volta eseguita questa operazione, qualsiasi file precedentemente serializzato con lo spazio dei nomi originale non viene più deserializzato. Ricevo la seguente eccezione:

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

Questo ha perfettamente senso. Ho cambiato lo spazio dei nomi. Sto bene con quello. Tuttavia, sembra che debba esserci un modo per dire allo DataContractSerializer di andare avanti e deserializzare quei dati anche se gli spazi dei nomi non corrispondono.

+0

Perché si desidera specificare una stringa vuota per uno spazio dei nomi nell'attributo DataContract? Cosa stai guadagnando facendo così? –

+2

Guadagno non essere legato allo spazio dei nomi CLR della classe; e questo è davvero il problema qui. Questa classe sta cambiando il suo spazio dei nomi CLR e non voglio essere legato a questi dettagli di implementazione. Potrei, ovviamente, definire un valore di spazio dei nomi xml che potrei mantenere costante. Ma per questa implementazione non vedo il vantaggio di farlo semplicemente rimuovendo lo spazio dei nomi xml. Questo viene utilizzato per la serializzazione di file semplice. – harlam357

risposta

15

Un modo possibile è avvolgere il lettore utilizzato dal serializzatore in un lettore che mappa il vecchio spazio dei nomi in quello nuovo, come mostrato di seguito. Un sacco di codice, ma soprattutto banale.

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

Questo ha funzionato alla grande! Stavo attaccando il problema al livello sbagliato. Grazie mille! Ho alcuni tipi di dati più complessi che contengono istanze di 'Dictionary ' che si sono rivelate un po 'più difficili. I tag per ogni KVP sono cambiati, presumo in base alla modifica del namespace, in quanto tale: '' a ''. Ho dovuto eseguire una conversione manuale su questi file, ma va bene. Questi file/tipi rappresentano una minoranza di ciò che deve essere letto. – harlam357

Problemi correlati