I've got this code:
[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 ) );
}
}
The first test works, but when I run the second I get this error:
System.InvalidOperationException : There is an error in XML document (2, 9). ----> System.InvalidOperationException : The specified type was not recognized: name='Hello', namespace='', at .
Instead of getting this error I would like it to ignore not recognized types. Is there any way to do this?
Yes, you can tell the XmlSerializer to ignore namespaces during de-serialization. Note this is the kind of thing I meant. You are not telling the XmlSerializer to ignore namespaces - you are giving it XML that has no namespaces.
XML Serialization Considerations Type identity and assembly information are not included. Only public properties and fields can be serialized. Properties must have public accessors (get and set methods). If you must serialize non-public data, use the DataContractSerializer class rather than XML serialization.
Deserialization is the process of reading an XML document and constructing an object that is strongly typed to the XML Schema (XSD) of the document. Before deserializing, an XmlSerializer must be constructed using the type of the object that is being deserialized.
XmlSerializer Class (System. Xml. Serialization)
Generic solution for similar problems:
Have a look at unknown element event (link) and unknown attribute event (link) and see if they solve the problems, or we have to get dirty. Read on...
Working solution for this problem
Bear in mind that that I have no idea what your task is, AFAIK it is serializing xml into your datastructure. If you can change the datastructure I would recommend you to have a look at Linq2XML and create a smart factory for your purposes.
[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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With