2012-10-30 5 views
6

ich diesen Code haben:ignorieren unbekannte Typen wenn xml Deserialisieren

[XmlType("Metadata")] 
[Serializable] 
public class MetadataContainer : List<MetadataBase> 
{ 
} 

[XmlType("Meta")] 
[XmlInclude(typeof(ReadonlyMetadata))] 
[Serializable] 
public abstract class MetadataBase 
{ 
} 

[XmlType("Readonly")] 
[Serializable] 
public class ReadonlyMetadata : MetadataBase 
{ 
} 

[TestFixture] 
public class SerializationTests 
{ 
    [Test] 
    public void Can_deserialize_with_known_type() 
    { 
     const string text = @"<Metadata xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""> 
         <Meta xsi:type=""Readonly"" /> 
        </Metadata>"; 

     var serializer = new XmlSerializer(typeof(MetadataContainer)); 
     var metas = (MetadataContainer)serializer.Deserialize(XmlReader.Create(new StringReader(text))); 

     Assert.That(metas.Count, Is.EqualTo(1)); 
     Assert.That(metas.First(), Is.InstanceOf<ReadonlyMetadata>()); 
    } 

    [Test] 
    public void Can_deserialize_with_unknown_type() 
    { 
     const string text = @"<Metadata xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""> 
         <Meta xsi:type=""Hello"" /> 
        </Metadata>"; 

     var serializer = new XmlSerializer(typeof(MetadataContainer)); 
     var metas = (MetadataContainer)serializer.Deserialize(XmlReader.Create(new StringReader(text))); 

     Assert.That(metas.Count, Is.EqualTo(0)); 
    } 
} 

Der erste Test funktioniert, aber wenn ich den zweiten Lauf bekomme ich diesen Fehler:

System.InvalidOperationException : There is an error in XML document (2, 9). ----> System.InvalidOperationException : The specified type was not recognized: name='Hello', namespace='', at .

Statt dies zu bekommen Fehler Ich möchte, dass nicht erkannte Typen ignoriert werden. Gibt es eine Möglichkeit, dies zu tun?

+0

Ich dachte, dies ein Fall von der Anmeldung zu einem oder mehreren der [ 'Unknown'- Ereignisse] sein würde (http://msdn.microsoft.com/en-us/ Bibliothek/0a51hxdw.aspx), aber beim Versuch es scheint nicht zu helfen. Geheimnisvoll. – AakashM

+0

Ich dachte auch, dass die Ergebnisse seltsam sind. Ich habe jedoch keine Lösung gefunden. – flindeberg

Antwort

3

generische Lösung für ähnliche Probleme:

Werfen Sie einen Blick auf unknown element event (link) und unknown attribute event (link) und sehen, ob sie die Probleme lösen, oder wir haben schmutzig. Lesen Sie weiter ...

Arbeitslösung für dieses Problem

Beachten Sie, dass, dass ich keine Ahnung, was Ihre Aufgabe ist es, AFAIK es xml in die Datenstruktur ist die Serialisierung. Wenn Sie die Datenstruktur ändern können, würde ich Ihnen empfehlen, sich Linq2XML anzuschauen und eine Smart Factory für Ihre Zwecke zu erstellen.

[TestMethod] 
public void TestLinq2Xml() 
{ 
    const string text = @"<Metadata xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""> 
          <Meta xsi:type=""Readonly"" /> 
          <Meta xsi:type=""Garbage"" /> 
         </Metadata>"; 

    // Get the "names" of all implementors of MetadataBase 
    var types = AppDomain.CurrentDomain.GetAssemblies().ToList() 
    .SelectMany(s => s.GetTypes()) 
     .Where(p => typeof(MetadataBase).IsAssignableFrom(p) && !p.IsAbstract && !p.IsInterface) 
     .Where(t => t.GetCustomAttributes(typeof(XmlTypeAttribute), false).Any()) 
     .Select(t => t.GetCustomAttributes(typeof(XmlTypeAttribute), false) 
      .Cast<XmlTypeAttribute>().First().TypeName); 

    // Create a parser 
    var parser = new XmlSerializer(typeof(MetadataBase)); 

    // Create metadatacontainer to fill 
    var metas = new MetadataContainer(); 
    // Fill it with matching from from the XML 
    metas.AddRange((from t in XDocument.Parse(text).Descendants("Meta") 
       where types.Contains(t.Attribute(XName.Get("type", "http://www.w3.org/2001/XMLSchema-instance")).Value) 
       select (MetadataBase)parser.Deserialize(t.CreateReader())).ToList()); 

    // Should be one guy present 
    Assert.AreEqual(metas.Count, 1); 
} 
0

Erfassen Sie alle unbekannten Elemente in einem Array. Sie können immer noch mit ihnen arbeiten und versuchen, später zu deserialisieren, aber dies ermöglicht die Deserialisierung. Sie benötigen dies in jeder von Ihnen definierten Klasse, um Ihre Elemente zu deserialisieren, wenn Sie vermuten, dass unbekannte Elemente vorhanden sind.

Per http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlanyelementattribute.aspx:

Public Class XClass 
    ' Apply the XmlAnyElementAttribute to a field returning an array 
    ' of XmlElement objects. 
    <XmlAnyElement()> Public AllElements() As XmlElement 
End Class 'XClass 
+1

Downvotes sind in Ordnung, aber bitte hinterlassen Sie Feedback, um mir zu helfen, meine Antwort zu überarbeiten. – VoteCoffee

+0

Sehr interessante Antwort. Muss das ausprobieren. – AnthonyVO

Verwandte Themen