2012-10-30 14 views
6

ho questo codice:Ignora tipi sconosciuti quando la deserializzazione XML

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

Il primo test funziona, ma quando ho eseguito il secondo ottengo questo errore:

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

Invece di ottenere questo errore Mi piacerebbe che ignorasse i tipi non riconosciuti. C'è un modo per fare questo?

+0

ho pensato che questo sarebbe un caso di sottoscrizione di uno o più dei [ 'eventi Unknown'-] (http://msdn.microsoft.com/en-us/ library/0a51hxdw.aspx), ma a provarlo sembra non aiutare. Misterioso. – AakashM

+0

Ho pensato anche che, comunque, i risultati sono strani. Non sono riuscito a trovare una soluzione però. – flindeberg

risposta

3

soluzione generica per problemi simili:

Dai un'occhiata alla unknown element event (link) e unknown attribute event (link) e vedere se risolvono i problemi, o dobbiamo sporcarsi. Continua a leggere ...

Soluzione di lavoro per questo problema

Tenete a mente che che non ho idea di che cosa il vostro compito è, per quanto ne so è la serializzazione XML nel vostro datastructure. Se è possibile modificare la struttura dei dati, consigliamo di dare un'occhiata a Linq2XML e creare una fabbrica intelligente per i propri scopi.

[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

Catturare tutti gli elementi sconosciuti in un array. Puoi ancora lavorare con loro e provare a deserializzare in seguito, ma ciò consente di completare la deserializzazione. Ne avrai bisogno in ogni classe che definisci per deserializzare i tuoi elementi in cui sospetti che ci saranno elementi sconosciuti.

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

I downvotes vanno bene, ma si prega di lasciare un feedback per aiutarmi a rivedere la mia risposta. – VoteCoffee

+0

Risposta molto interessante. Dovrà provarlo. – AnthonyVO

Problemi correlati