忽略在xml反序列化时未知的类型

8

我有这段代码:

[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:XML文档中存在错误(2,9)。 ----> System.InvalidOperationException :指定的类型未被识别:name='Hello',namespace=''。
我希望它可以忽略未被识别的类型而不是抛出异常。是否有任何方式实现这一点?

我原以为这只是订阅一个或多个Unknown- events的情况,但尝试后似乎并没有帮助。神秘。 - AakashM
我也认为结果很奇怪,但是我没有找到解决方案。 - flindeberg
2个回答

3

类似问题的通用解决方案:

看看未知元素事件(链接)未知属性事件(链接)是否能解决问题,否则我们需要采取更复杂的方法。请继续阅读...

此问题的解决方案

请注意,我不知道你的任务是什么,只知道它将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
踩一下是可以的,但请留下反馈帮助我修改我的答案。 - VoteCoffee
非常有趣的答案。我得试试看。 - AnthonyVO

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接