Here is my first attempt at validating XML with XSD.
The XML file to be validated:
<?xml version="1.0" encoding="utf-8" ?>
<config xmlns="Schemas" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="config.xsd">
<levelVariant>
<filePath>SampleVariant</filePath>
</levelVariant>
<levelVariant>
<filePath>LegendaryMode</filePath>
</levelVariant>
<levelVariant>
<filePath>AmazingMode</filePath>
</levelVariant>
</config>
The XSD, located in "Schemas/config.xsd" relative to the XML file to be validated:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="config">
<xs:complexType>
<xs:sequence>
<xs:element name="levelVariant">
<xs:complexType>
<xs:sequence>
<xs:element name="filePath" type="xs:anyURI">
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Right now, I just want to validate the XML file precisely as it appears currently. Once I understand this better, I'll expand more. Do I really need so many lines for something as simple as the XML file as it currently exists?
The validation code in C#:
public void SetURI(string uri)
{
XElement toValidate = XElement.Load(Path.Combine(PATH_TO_DATA_DIR, uri) + ".xml");
// begin confusion
// exception here
string schemaURI = toValidate.Attributes("xmlns").First().ToString()
+ toValidate.Attributes("xsi:noNamespaceSchemaLocation").First().ToString();
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add(null, schemaURI);
XDocument toValidateDoc = new XDocument(toValidate);
toValidateDoc.Validate(schemas, null);
// end confusion
root = toValidate;
}
Running the above code gives this exception:
The ':' character, hexadecimal value 0x3A, cannot be included in a name.
Any illumination would be appreciated.
Rather than using the XDocument.Validate extension method, I would use an XmlReader which can be configured to process an inline schema via XmlReaderSettings. You could do some thing like the following code.
public void VerifyXmlFile(string path)
{
// configure the xmlreader validation to use inline schema.
XmlReaderSettings config = new XmlReaderSettings();
config.ValidationType = ValidationType.Schema;
config.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
config.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
config.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
config.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
// Get the XmlReader object with the configured settings.
XmlReader reader = XmlReader.Create(path, config);
// Parsing the file will cause the validation to occur.
while (reader.Read()) ;
}
private void ValidationCallBack(object sender, ValidationEventArgs vea)
{
if (vea.Severity == XmlSeverityType.Warning)
Console.WriteLine(
"\tWarning: Matching schema not found. No validation occurred. {0}",
vea.Message);
else
Console.WriteLine("\tValidation error: {0}", vea.Message);
}
The code above assumes the following using statements.
using System.Xml;
using System.Xml.Schema;
Just to keep this simple I did not return a boolean or a collection of validation errors, you could easily modify this to do so.
Note: I modified your config.xml and config.xsd to get them to validate. These are the changes I made.
config.xsd:
<xs:element maxOccurs="unbounded" name="levelVariant">
config.xml:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="config.xsd">
Following is out of a working sample:
Usage:
XMLValidator val = new XMLValidator();
if (!val.IsValidXml(File.ReadAllText(#"d:\Test2.xml"), #"D:\Test2.xsd"))
MessageBox.Show(val.Errors);
Class:
public class CXmlValidator
{
private int nErrors = 0;
private string strErrorMsg = string.Empty;
public string Errors { get { return strErrorMsg; } }
public void ValidationHandler(object sender, ValidationEventArgs args)
{
nErrors++;
strErrorMsg = strErrorMsg + args.Message + "\r\n";
}
public bool IsValidXml(string strXml/*xml in text*/, string strXsdLocation /*Xsd location*/)
{
bool bStatus = false;
try
{
// Declare local objects
XmlTextReader xtrReader = new XmlTextReader(strXsdLocation);
XmlSchemaCollection xcSchemaCollection = new XmlSchemaCollection();
xcSchemaCollection.Add(null/*add your namespace string*/, xtrReader);//Add multiple schemas if you want.
XmlValidatingReader vrValidator = new XmlValidatingReader(strXml, XmlNodeType.Document, null);
vrValidator.Schemas.Add(xcSchemaCollection);
// Add validation event handler
vrValidator.ValidationType = ValidationType.Schema;
vrValidator.ValidationEventHandler += new ValidationEventHandler(ValidationHandler);
//Actual validation, read conforming the schema.
while (vrValidator.Read()) ;
vrValidator.Close();//Cleanup
//Exception if error.
if (nErrors > 0) { throw new Exception(strErrorMsg); }
else { bStatus = true; }//Success
}
catch (Exception error) { bStatus = false; }
return bStatus;
}
}
The above code validates following xml(code3) against xsd(code4).
<!--CODE 3 - TEST1.XML-->
<address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test1.xsd">
<name>My Name</name>
<street>1, My Street Address</street>
<city>Far</city>
<country>Mali</country>
</address>
<!--CODE 4 - TEST1.XSD-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
In validating against your xml/xsd I get of errors different than yours; I think this can help you continue(add/remove xml elements) from here:
You may also try the reverse process; try generating the schema from your xml and compare with your actual xsd - see the difference; and the easiest way to do that is to use generate schema using VS IDE. Following is how you'd do that:
Hope this helps.
--EDIT--
This is upon John's request, please see updated code using non deprecated methods:
public bool IsValidXmlEx(string strXmlLocation, string strXsdLocation)
{
bool bStatus = false;
try
{
// Declare local objects
XmlReaderSettings rs = new XmlReaderSettings();
rs.ValidationType = ValidationType.Schema;
rs.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation | XmlSchemaValidationFlags.ReportValidationWarnings;
rs.ValidationEventHandler += new ValidationEventHandler(rs_ValidationEventHandler);
rs.Schemas.Add(null, XmlReader.Create(strXsdLocation));
using (XmlReader xmlValidatingReader = XmlReader.Create(strXmlLocation, rs))
{ while (xmlValidatingReader.Read()) { } }
////Exception if error.
if (nErrors > 0) { throw new Exception(strErrorMsg); }
else { bStatus = true; }//Success
}
catch (Exception error) { bStatus = false; }
return bStatus;
}
void rs_ValidationEventHandler(object sender, ValidationEventArgs e)
{
if (e.Severity == XmlSeverityType.Warning) strErrorMsg += "WARNING: " + Environment.NewLine;
else strErrorMsg += "ERROR: " + Environment.NewLine;
nErrors++;
strErrorMsg = strErrorMsg + e.Exception.Message + "\r\n";
}
Usage:
if (!val.IsValidXmlEx(#"d:\Test2.xml", #"D:\Test2.xsd"))
MessageBox.Show(val.Errors);
else
MessageBox.Show("Success");
Test2.XML
<?xml version="1.0" encoding="utf-8" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test2.xsd">
<levelVariant>
<filePath>SampleVariant</filePath>
</levelVariant>
<levelVariant>
<filePath>LegendaryMode</filePath>
</levelVariant>
<levelVariant>
<filePath>AmazingMode</filePath>
</levelVariant>
</config>
Test2.XSD (Generated from VS IDE)
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="config">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="levelVariant">
<xs:complexType>
<xs:sequence>
<xs:element name="filePath" type="xs:anyURI">
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
This is guaranteed to work!
Your code to extract the schema location looks weird. Why do you get the value of the xmlns attribute and concatenate it with the value of the xsi:noNamespaceSchemaLocation attribute? The exception is caused by the fact that you cannot specify a prefix in a call to Attributes; you need to specify the desired XNamespace.
Try this (untested):
// Load document
XDocument doc = XDocument.Load("file.xml");
// Extract value of xsi:noNamespaceSchemaLocation
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
string schemaURI = (string)doc.Root.Attribute(xsi + "noNamespaceSchemaLocation");
// Create schema set
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("Schemas", schemaURI);
// Validate
doc.Validate(schemas, (o, e) =>
{
Console.WriteLine("{0}", e.Message);
});
Related
I am using Visual Studio 2015.
I apologize for the poorly named "firstName" element. It should have been "fullName", but since I already generated the class for the schema, and this is just for my own learning, I left it as is.
I have an XML schema here:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="address-schema"
targetNamespace="http://tempuri.org/address-schema.xsd"
elementFormDefault="qualified"
attributeFormDefault="qualified"
xmlns:addr="http://tempuri.org/address-schema.xsd"
xmlns:mstns="http://tempuri.org/address-schema.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element name="firstName">
<xs:complexType>
<xs:sequence>
<xs:element name="first" type="addr:nameComponent"/>
<xs:element name="middle" type="addr:nameComponent" minOccurs="0"/>
<xs:element name="last" type="addr:nameComponent"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="nameComponent">
<xs:simpleContent>
<xs:extension base="xs:string"/>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
And an XML file that I think conforms to the schema:
<?xml version="1.0" encoding="utf-8" ?>
<addr:address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tempuri.org/address-schema.xsd address-schema.xsd"
xmlns:addr="http://tempuri.org/address-schema.xsd">
<addr:firstName>
<addr:first>Some</addr:first>
<addr:middle>Bodys</addr:middle>
<addr:last>Name</addr:last>
</addr:firstName>
</addr:address>
And the code that is attempting to validate the XML is here (note that the "address" class that the XML file is getting deserialized into is an auto generated class from xsd.exe):
address address;
var xmlSchemaSerializer = new XmlSerializer(typeof(XmlSchema));
var addressXmlSerializer = new XmlSerializer(typeof(address));
var schemas = new XmlSchemaSet();
XmlSchema schema;
using (var xsdStream = File.OpenRead("address-schema.xsd"))
{
schema = (XmlSchema)xmlSchemaSerializer.Deserialize(xsdStream);
}
schemas.Add(schema);
var settings = new XmlReaderSettings
{
Schemas = schemas,
ValidationType = ValidationType.Schema,
ValidationFlags = XmlSchemaValidationFlags.ProcessIdentityConstraints | XmlSchemaValidationFlags.ReportValidationWarnings | XmlSchemaValidationFlags.ProcessInlineSchema | XmlSchemaValidationFlags.ProcessSchemaLocation
};
settings.ValidationEventHandler += (sender, arguments) =>
{
throw new XmlSchemaValidationException(arguments.Message);
};
using(Stream addressXmlStream = File.OpenRead("address-doc.xml"))
using (XmlReader reader = XmlReader.Create(addressXmlStream, settings))
{
address = (address)addressXmlSerializer.Deserialize(reader);
}
Console.WriteLine(address.firstName.first.Value == "Some" ? "Success!" : "Fail");
Console.ReadKey();
The exception ('System.Xml.Schema.XmlSchemaValidationException'The global element 'http://tempuri.org/address-schema.xsd:address' has already been declared.) is thrown in the ValidationEventHandler.
Any help or suggestions would be appreciated. Thanks in advance!
The cause of your exception is that your document has a schema location hint that loads the schema, but you've already loaded it.
Either don't pre-load the schema or remove the xsi:schemaLocation attribute from your document.
I have to parse a XML where the xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" namespace is missing, so the xml looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<program>
<scriptList>
<script type="StartScript">
<isUserScript>false</isUserScript>
</script>
</scriptList>
</program>
but should look like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<program xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<scriptList>
<script xsi:type="StartScript">
<isUserScript>false</isUserScript>
</script>
</scriptList>
</program>
The type attribute ensures the correct subclass e.g.
class StartScript : script
{...}
The parser is auto generated from an handwritten xsd via $> xsd.exe a.xsd /classes (.Net).
Here is the xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="qualified">
<!-- Main element -->
<xs:element name="program">
<xs:complexType>
<xs:sequence>
<xs:element name="scriptList">
<xs:complexType>
<xs:sequence>
<xs:element name="script" type="script" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="script" />
<xs:complexType name="StartScript">
<xs:complexContent>
<xs:extension base="script">
<xs:all>
<xs:element name="isUserScript" type="xs:boolean"></xs:element>
</xs:all>
</xs:extension>
</xs:complexContent>
</xs:complexType>
A simple solution is to run a string-replace (" type=\"" to " xsi:type=\"") on the input XML but this is pretty ugly.
Is there a better solution?
You can load your XML into an intermediate LINQ to XML XDocument, fix the attribute namespaces on the <script> elements, then deserialize directly to your final class:
// Load to intermediate XDocument
XDocument xDoc;
using (var reader = XmlReader.Create(f))
xDoc = XDocument.Load(reader);
// Fix namespace of "type" attributes
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
foreach (var element in xDoc.Descendants("script"))
{
var attr = element.Attribute("type");
if (attr == null)
continue;
var newAttr = new XAttribute(xsi + attr.Name.LocalName, attr.Value);
attr.Remove();
element.Add(newAttr);
}
// Deserialize directly to final class.
var program = xDoc.Deserialize<program>();
Using the extension method:
public static class XObjectExtensions
{
public static T Deserialize<T>(this XContainer element, XmlSerializer serializer = null)
{
if (element == null)
throw new ArgumentNullException();
using (var reader = element.CreateReader())
return (T)(serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader);
}
}
I am building a web service in .NET that will pass data back and forth via XML. I would like to validate the XML in the incoming requests using an XSD that I have defined.
Here is the XSD:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="POSearch">
<xs:sequence minOccurs="0" maxOccurs="10">
<xs:element name="POID" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Here is the XML:
<POSearch>
<POID>1</POID>
<POID>2</POID>
</POSearch>
Here is the validation code in C#:
static void Main(string[] args){
XmlSchemaSet iSchemas = new XmlSchemaSet();
iSchemas.Add(string.Empty, #"...xsd file location");
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
settings.Schemas.Add(iSchemas);
XmlReader reader = XmlReader.Create(#"...xml file location", settings);
try {
while(reader.Read())
;
}
catch(Exception ex) {
Console.WriteLine(ex.Message);
}
}
private static void ValidationCallBack(object sender, ValidationEventArgs args) {
if(args.Severity == XmlSeverityType.Warning)
Console.WriteLine("\tWarning: Matching schema not found. No validation occurred." + args.Message);
else
Console.WriteLine("\tValidation error: " + args.Message);
}
I feel like I had this working before and I'm not completely sure why this isn't working now. Whenever I run this I get the following Exception Message:
Validation error: The 'POSearch' element is not declared.
Have I defined my XSD wrong? Is my validation code wrong? The elements are all clearly there. Any help pointing me in the right direction is greatly appreciated.
You have the type declared but no element declared of that type.
Add an element declaration:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="POSearch" type="POSearch"/>
<xs:complexType name="POSearch">
<xs:sequence minOccurs="0" maxOccurs="10">
<xs:element name="POID" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Try this:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="POSearch">
<xs:sequence minOccurs="0" maxOccurs="10">
<xs:element name="POID" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
<xs:element name="POSearch" type="POSearch"/>
</xs:schema>
I have 2 xsd files content in a dictionary. I want to merge both the contents and create one xsd file.
1st xsd content from dictionary has a import tag pointing to 2nd xsd in the dictionary.
1st xsd -
<?xml version="1.0" encoding="IBM437"?>
<xs:schema xmlns:tns="http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML" targetNamespace="http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/Enr
ichedMessageXML" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import schemaLocation="COMP.EDI._00401._810.Schemas.Headers" namespace="http://EDI/Headers" />
<xs:element name="X12EnrichedMessage">
<xs:complexType>
<xs:sequence>
<xs:element xmlns:q1="http://EDI/Headers" ref="q1:Headers" />
<xs:element name="TransactionSet">
<xs:complexType>
<xs:sequence>
<xs:element xmlns:q2="http://schemas.microsoft.com/BizTalk/EDI/X12/2006" ref="q2:X12_00401_810" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
2nd sxd -
<?xml version="1.0" encoding="IBM437"?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns="http://EDI/Headers" xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://EDI/Headers">
<xs:element name="Headers">
// Some content here
</xs:element>
</xs:schema>
desired xsd I want is the merger of both the xsd documents.
I am following this : http://msdn.microsoft.com/en-us/library/ms256237%28v=vs.110%29.aspx article, I am able to add the schemas to schemaset object also, but when I am using RecurseExternals function (from the article) this is not showing the merged xsd but 2 different xsd.
my block of code -
XmlSchemaSet schemaSet = new XmlSchemaSet();
// This prevents schemaLocation and Namespace warnings
// at this point we already have the schema from schemaLocation.
//schemaSet.XmlResolver = null;
schemaSet.ValidationEventHandler += new ValidationEventHandler(ValidationCallback);
// add schema in schema set from schemacollection object
foreach (var item in schemaCollection)
{
schemaSet.Add(item.Key, new XmlTextReader(new StringReader(item.Value)));
}
schemaSet.Compile();
XmlSchema mainXmlSchema = null;
XmlSchemaImport import = new XmlSchemaImport();
foreach (XmlSchema sch in schemaSet.Schemas())
{
// pick the main schema from the schemaset to include
// other schemas in the collection.
if (sch.TargetNamespace == mainSchemaNS)
{
mainXmlSchema = sch;
}
else
{
import.Namespace = sch.TargetNamespace;
import.Schema = sch;
mainXmlSchema.Includes.Add(import);
}
}
schemaSet.Reprocess(mainXmlSchema);
schemaSet.Compile();
RecurseExternals(mainXmlSchema);
am I doing anything wrong ?
I'm trying to deserialize XML into a C# object
I am getting the error:There is an error in XML document (3, 2).
Cannot seem to fix it! Here is the code:
The XSD is:
<?xml version="1.0" encoding="utf-8" ?>
<!--Created with Liquid XML Studio 2012 Developer Edition (Trial) 10.0.2.3955 (http://www.liquid-technologies.com)-->
<xs:schema xmlns:tns="http://www.adamroe.com/xsd/cameras.xsd" elementFormDefault="qualified" targetNamespace="http://www.adamroe.com/xsd/cameras.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="CameraBase">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="Cameras">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="Camera" type="tns:CameraType" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="CameraType">
<xs:sequence>
<xs:element name="Make" type="xs:string" />
<xs:element name="Model" type="xs:string" />
<xs:element name="Variable1" type="xs:double" />
<xs:element name="Variable2" type="xs:double" />
</xs:sequence>
</xs:complexType>
</xs:schema>
The XML is:
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid XML Studio 2012 Developer Edition (Trial) 10.0.2.3955 (http://www.liquid-technologies.com) -->
<aroe:CameraBase xmlns:aroe="http://www.adamroe.com/xsd/cameras.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.adamroe.com/xsd/cameras.xsd C:\Users\Adam\Desktop\Cameras.xsd">
<aroe:Cameras>
<aroe:Camera>
<aroe:Make>SONY</aroe:Make>
<aroe:Model>DSC-W130</aroe:Model>
<aroe:Variable1>0.6352</aroe:Variable1>
<aroe:Variable2>22.375</aroe:Variable2>
</aroe:Camera>
<aroe:Camera>
<aroe:Make>Panasonic</aroe:Make>
<aroe:Model>DMC-FX30</aroe:Model>
<aroe:Variable1>0.8869</aroe:Variable1>
<aroe:Variable2>24.73</aroe:Variable2>
</aroe:Camera>
<aroe:Camera>
<aroe:Make>Olympus</aroe:Make>
<aroe:Model>X450</aroe:Model>
<aroe:Variable1>0.6003</aroe:Variable1>
<aroe:Variable2>20.654</aroe:Variable2>
</aroe:Camera>
<aroe:Camera>
<aroe:Make>Fujifilm</aroe:Make>
<aroe:Model>FinePix S9600</aroe:Model>
<aroe:Variable1>1.0024</aroe:Variable1>
<aroe:Variable2>35.704</aroe:Variable2>
</aroe:Camera>
<aroe:Camera>
<aroe:Make>Canon</aroe:Make>
<aroe:Model>EOS 400D</aroe:Model>
<aroe:Variable1>1.5143</aroe:Variable1>
<aroe:Variable2>69.409</aroe:Variable2>
</aroe:Camera>
</aroe:Cameras>
</aroe:CameraBase>
The class is:
public class Camera
{
public string Make;
public string Model;
public double Variable1;
public double Variable2;
}
Deserialize code:
public class PopulateXML
{
public void DeserializeObject(string filenameXML)
{
Console.WriteLine("Reading with XmlReader");
// Create an instance of the XmlSerializer specifying type and namespace.
XmlSerializer serializer = new
XmlSerializer(typeof(List<Camera>));
// A FileStream is needed to read the XML document.
FileStream fs = new FileStream(filenameXML, FileMode.Open);
XmlReader reader = new XmlTextReader(fs);
// Declare an object variable of the type to be deserialized.
List<Camera> i;
// Use the Deserialize method to restore the object's state.
i = (List<Camera>)serializer.Deserialize(reader);
}
}
Main:
PopulateXML x = new PopulateXML();
// Read a purchase order.
x.DeserializeObject("Cameras.xml");
The exception is thrown on: i = (List)serializer.Deserialize(reader);
XmlSerializer serializer = new XmlSerializer(typeof(Camera));
Stream fs = File.OpenRead(filenameXMLpath);
// Use the Deserialize method to restore the object's state.
Camera cam = serializer.Deserialize(fs) as Camera;
This will definitely work for you. In your case it was not working because you were type casting it to the incorrect data type i.e., List. This error generally pops-up whenever developer type cast deserialized object to incorrect data type.
You could use LinqToXml and these extensions: http://searisen.com/xmllib/extensions.wiki to parse the Xml easily.
XElement root = XElement.Load(file); // or .Parse(string)
List<Camera> cameras = root.GetEnumerable("Cameras/Camera", x => new Camera()
{
Make = x.Get("Make", string.Empty),
Model = x.Get("Model", string.Empty),
Variable1 = x.Get<double>("Variable1", 0),
Variable2 = x.Get<double>("Variable2", 0)
}).ToList();
PS I've tested it and it works on your xml.
PSS Consider adding this attribute [DebuggerDisplay("{Make} - {Model}")] to your camera class to make viewing the list/array in the debugger nicer.