问题
I've been trying to deserialize an xml file in C# with classes generated from schemas in xsd.exe. Unfortunately only part of the file is being properly deserialized, the rest is returned as null for reasons I can't work out.
My process is as follows: Starting with the myschema.xsd file from which the C# code is generated:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mc="myschema:common" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ttl="http://www.myuri.org/myschema" targetNamespace="http://www.myuri.org/myschema" elementFormDefault="qualified" attributeFormDefault="unqualified">
and the imported parentschema.xsd file is so:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:mc="myschema:common" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="myschema:common" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="toplevel">
<xs:complexType>
<xs:sequence>
<xs:element ref="mc:toplevel_header" minOccurs="0"/>
<xs:element ref="mc:body"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="toplevel_header">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:anyURI"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="body" type="mc:body" abstract="true"/>
<xs:complexType name="body">
<xs:attribute name="id" type="xs:ID" use="required"/>
</xs:complexType>
<xs:element name="Entity" type="mc:Entity" abstract="true"/>
<xs:complexType name="Entity" abstract="true">
<xs:attribute name="href" type="xs:anyURI" use="optional"/>
</xs:complexType>
</xs:schema>
I'm passing the two above schema files to xsd.exe:
>xsd.exe /c myschema.xsd parentschema.xsd
which generates a myschema_parentschema.cs file
To test it I'm trying to deserialize a sample xml file:
<?xml version=\"1.0\" encoding="UTF-8"?>
<toplevel version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="myschema:common"
xsi:schemaLocation="myschema:common http://www.myuri.org/parentschema.xsd">
<toplevel_header>
<name>MyName</name>
</toplevel_header>
<body id="body_1"
xmlns="http://www.myuri.org/schema"
xmlns:mc="myschema:common"
xsi:schemaLocation="http://www.myuri.org/myschema http://www.myuri.org/myschema.xsd">
<Foo href="http://www.google.com">
</Foo>
</body>
</toplevel>
which I'm passing to the following XmlSerializer code, where reader is an XmlReader for the above xml file:
XmlSerializer xs = new XmlSerializer ( typeof ( toplevel ) );
object deserializedObject = xs.Deserialize( reader );
toplevel fooBar = (toplevel)deserializedObject;
Assert.AreEqual( "MyName", fooBar.toplevel_header.name ); //passes OK
Assert.IsNotNull( fooBar.body ); //<--------FAIL
Why does the deserialized object have a null body property, and how do I get it to deserialize the Foo element properly?
回答1:
There's a typo in your parentschema.xsd. You're closing the <xs:element>
tag prematurely for the body tag:
<xs:element name="body" type="mc:body" abstract="true"/>
You also define the body as abstract which I think is a mistake (if I'm reading the XML properly).
The whole definition (based on your XML) should look something like:
<xs:element name="body" type="mc:body" abstract="true">
<xs:complexType>
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:sequence>
<xs:element type="Foo" type="xs:anyURI" />
</xs:sequence>
</xs:complexType>
</xs:element>
回答2:
I followed the same steps as you, and it looks like your schema and the XML file that you're deserializing are not matching. Here's what I did:
static void Main(string[] args)
{
var xs = new XmlSerializer(typeof(toplevel));
// test saving to xml first...
var tl = new toplevel();
tl.toplevel_header = new toplevel_header();
tl.toplevel_header.name = "MyName";
tl.body = new body();
tl.body.id = "body id...";
// output to console first...
var cw = Console.OpenStandardOutput();
xs.Serialize(cw, tl);
Console.WriteLine();
Console.WriteLine();
// save to file...
var fw = File.CreateText("test.xml");
xs.Serialize(fw, tl);
fw.Close();
// read file...
var fr = File.Open("test.xml", FileMode.Open, FileAccess.Read);
var obj = xs.Deserialize(fr);
var fooBar = (toplevel)obj;
Console.WriteLine(fooBar.toplevel_header.name);
Console.WriteLine(fooBar.body.id);
Console.ReadLine();
}
The XML that the serializer generated was this:
<?xml version="1.0" encoding="utf-8"?>
<toplevel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="myschema:common">
<toplevel_header>
<name>MyName</name>
</toplevel_header>
<body id="body id..." />
</toplevel>
The XML clearly does not match the input XML file you are using... Hopefully this helps you along your way!
回答3:
Looking at your sample xml I noticed a inconsistency which is the reason why the XmlSerializer is not coming up with what you expect:
<toplevel version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xlink="http://www.w3.org/1999/xlink"
***xmlns="myschema:common"***
xsi:schemaLocation="myschema:common http://www.myuri.org/parentschema.xsd">
<toplevel_header>
<name>MyName</name>
</toplevel_header>
<body id="body_1"
***xmlns="http://www.myuri.org/schema"***
***xmlns:mc="myschema:common"***
xsi:schemaLocation="http://www.myuri.org/myschema http://www.myuri.org/myschema.xsd">
<Foo href="http://www.google.com">
</Foo>
</body>
</toplevel>
In your toplevel element you are defining xmlns="myschema:common", and yet in your body element you are defining xmlns="http://www.myuri.org/schema" and the next line is xmlns:mc="myschema:common". This means that the Foo element inside of the body is under a different namespace and the XmlSerializer will not find the element. When I deleted the xmlns declaration in the body element and changed the xmlns:mc declaration to xmlns, like so:
<?xml version="1.0" encoding="UTF-8"?>
<toplevel version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="myschema:common"
xsi:schemaLocation="myschema:common http://www.myuri.org/parentschema.xsd">
<toplevel_header>
<name>MyName</name>
</toplevel_header>
<body id="body_1"
xmlns="myschema:common"
xsi:schemaLocation="http://www.myuri.org/myschema http://www.myuri.org/myschema.xsd">
<Foo href="http://www.google.com">
</Foo>
</body>
</toplevel>
Having adjusted the sample xml as indicated the XmlSerializer created the toplevel object with a non-null body inside of it.
来源:https://stackoverflow.com/questions/2150055/xmlserializer-not-correctly-deserializing-schema-with-import