2012-06-18 18 views
19

Mam klasę danych, która jest serializowana z DataContractSerializer. Klasa używa atrybutu [DataContract] bez wyraźnej deklaracji Namespace. W związku z tym przestrzeń nazw w wynikowym pliku XML jest generowana w oparciu o przestrzeń nazw klasy.DataContractSerializer - zmień przestrzeń nazw i deserializuj plik powiązany ze starą przestrzenią nazw

Klasa zasadniczo wygląda następująco:

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

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

... i powstały 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> 

Teraz chcę zmienić nazw klasy (właściwie usunąć go) poprzez zmianę atrybut [DataContract] na [DataContract(Namespace = "")]. Jednakże, gdy już to zrobię, każdy plik poprzednio serializowany z oryginalną przestrzenią nazw, nie będzie już deserializowany. Otrzymuję następujący wyjątek:

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

to sens. Zmieniłem przestrzeń nazw. Nie przeszkadza mi to. Jednak wydaje się, że musi istnieć sposób, aby powiedzieć DataContractSerializer, aby kontynuować i deserializować te dane, nawet jeśli przestrzenie nazw się nie zgadzają.

+0

Dlaczego chcesz określić pusty ciąg dla przestrzeni nazw w atrybucie DataContract? Co zyskujesz, robiąc to? –

+2

Nie uzyskuję przywiązania do przestrzeni nazw CLR klasy; i to jest naprawdę problem tutaj. Ta klasa zmienia jego przestrzeń nazw CLR i nie chcę być związana z tą szczegółowością implementacji. Mógłbym oczywiście zdefiniować wartość przestrzeni nazw xml, którą mógłbym utrzymać na stałym poziomie. Ale dla tej implementacji nie widzę korzyści z tego, w przeciwieństwie do po prostu usuwania przestrzeni nazw xml. Jest to używane do prostego serializowania plików. – harlam357

Odpowiedz

15

Jednym z możliwych sposobów jest owinięcie czytnika używanego przez serializator w czytniku, który odwzorowuje stary obszar nazw na nowy, jak pokazano poniżej. Dużo kodu, ale głównie banalne.

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

To działało świetnie! Atakowałem problem na niewłaściwym poziomie. Dzięki wielkie! Mam bardziej złożone typy danych, które zawierają instancje 'Dictionary ', które okazały się nieco trudniejsze. Tagi dla każdego KVP uległy zmianie, zakładam na podstawie zmiany przestrzeni nazw, jako takie: '' to ''. Musiałem wykonać ręczną konwersję tych plików, ale to jest w porządku. Te pliki/typy stanowią mniejszość tego, co należy przeczytać. – harlam357

Powiązane problemy