2012-10-30 219 views
6

當我得到這個代碼忽略未知類型:反序列化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)); 
    } 
} 

第一個測試工作,但是當我運行第二個我得到這個錯誤:

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

非但沒有這樣的錯誤我希望它忽略未識別的類型。有沒有辦法做到這一點?

+0

我認爲這將是訂閱的一個或多個['Unknown'-事件]的的情況下(http://msdn.microsoft.com/en-us/ library/0a51hxdw.aspx),但嘗試它似乎沒有幫助。神祕。 – AakashM

+0

我也認爲,結果很奇怪。儘管我沒有設法找到解決方案。 – flindeberg

回答

3

類似的問題通用的解決方案:

看一看unknown element event (link)unknown attribute event (link),看看他們解決問題,或者我們變髒。閱讀...

工作解決這個問題

記住,我不知道你的任務是什麼,據我所知這是XML序列化到你的數據結構。如果您可以更改數據結構,我建議您查看Linq2XML併爲您的目的創建一個智能工廠。

[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

捕獲數組中的所有未知元素。你仍然可以和它們一起工作並嘗試稍後反序列化,但是這樣可以完成反序列化。如果您懷疑存在未知元素,則您需要在每個定義的類中對其進行反序列化。

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很好,但請留下意見,以幫助我修改我的答案。 – VoteCoffee

+0

非常有趣的答案。將不得不嘗試。 – AnthonyVO