All*_*est 6 .net c# xml-deserialization
我有这个代码:
[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 ) );
}
}
Run Code Online (Sandbox Code Playgroud)
第一个测试工作,但当我运行第二个测试时,我收到此错误:
System.InvalidOperationException:XML文档中存在错误(2,9).----> System.InvalidOperationException:无法识别指定的类型:name ='Hello',namespace ='',at.
我没有得到这个错误,而是希望忽略不识别的类型.有没有办法做到这一点?
类似问题的通用解决方案:
看一下未知元素事件(链接)和未知属性事件(链接),看看它们是否解决了问题,否则我们就得搞砸了。继续阅读...
这个问题的工作解决方案
请记住,我不知道您的任务是什么,据我所知,它将 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);
}
Run Code Online (Sandbox Code Playgroud)