Writing xsi:type attributes for Lists based on an abstract type

Jul 31, 2012 at 4:51 PM

Hi,

For the given example schema:

 

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
	<xs:complexType name="Base" abstract="1">
		<xs:sequence>
			<xs:element name="ReferenceID" type="xs:int"/>
			<xs:element name="ReferenceType" type="xs:string"/>
		</xs:sequence>
	</xs:complexType>
	<xs:complexType name="Case">
		<xs:complexContent>
			<xs:extension base="Base">
				<xs:sequence>
					<xs:element name="CaseNumber" type="xs:string"/>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>
	<xs:complexType name="Permit">
		<xs:complexContent>
			<xs:extension base="Base">
				<xs:sequence>
					<xs:element name="PermitNumber" type="xs:string"/>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>
	<xs:element name="Form">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="References" type="Base" minOccurs="0" maxOccurs="unbounded"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

 

So, there is a Form with an unbounded list References of type Base.

Base is an abstract type of which there are two concrete extensions, Case and Permit.

So, the following is valid example Xml generated by XmlSpy.

 

<?xml version="1.0" encoding="UTF-8"?>
<Form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<References xsi:type="Permit">
		<ReferenceID>0</ReferenceID>
		<ReferenceType>String</ReferenceType>
		<PermitNumber>String</PermitNumber>
	</References>
	<References xsi:type="Case">
		<ReferenceID>0</ReferenceID>
		<ReferenceType>String</ReferenceType>
		<CaseNumber>String</CaseNumber>
	</References>
</Form>

 

If I then generate class wrappers using Linq to Xsd, the following code works:

 

            Form altovaValid = Form.Load("AltovaValid.xml");

            Permit thePermit = (Permit)altovaValid.References[0];
            Console.WriteLine(thePermit.ToString());

            Case theCase = (Case)altovaValid.References[1];
            Console.WriteLine(theCase.ToString());

            Console.WriteLine(altovaValid.References[0] is Permit);

            Console.WriteLine(altovaValid.References[1] is Permit);

 

And produces:

 

<References xsi:type="Permit" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ReferenceID>0</ReferenceID>
  <ReferenceType>String</ReferenceType>
  <PermitNumber>String</PermitNumber>
</References>
<References xsi:type="Case" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ReferenceID>0</ReferenceID>
  <ReferenceType>String</ReferenceType>
  <CaseNumber>String</CaseNumber>
</References>
True
False

on the console.

 

Now, if I run this code:

 

            Form linqToXsdInvalid = new Form();

            linqToXsdInvalid.References.Add(new Permit()
            {
                ReferenceID = 0,
                ReferenceType = "string",
                PermitNumber = "string",
            });

            linqToXsdInvalid.References.Add(new Case()
            {
                ReferenceID = 0,
                ReferenceType = "string",
                CaseNumber = "string",
            });

            linqToXsdInvalid.Save("LinqToXsdInvalid.xml");

 

It produces this xml:

 

<?xml version="1.0" encoding="utf-8"?>
<Form>
  <References>
    <ReferenceID>0</ReferenceID>
    <ReferenceType>string</ReferenceType>
    <PermitNumber>string</PermitNumber>
  </References>
  <References>
    <ReferenceID>0</ReferenceID>
    <ReferenceType>string</ReferenceType>
    <CaseNumber>string</CaseNumber>
  </References>
</Form>

 

This Xml is invalid, if I assign a schema in XmlSpy and validate it it complains that Base is abstract, as it does not know that they are actually Permit and Case instances. The xsi:type attribute is missing.

The example code:

 

            linqToXsdInvalid.Save("LinqToXsdInvalid.xml");

            linqToXsdInvalid = Form.Load("LinqToXsdInvalid.xml");

            Permit thePermit = (Permit)linqToXsdInvalid.References[0];
            Console.WriteLine(thePermit.ToString());

            Case theCase = (Case)linqToXsdInvalid.References[1];
            Console.WriteLine(theCase.ToString());

            Console.WriteLine(linqToXsdInvalid.References[0] is Permit);

            Console.WriteLine(linqToXsdInvalid.References[1] is Permit);

Throws an invalid operation exception with "Cannot cast XElement to an abstract type" in

Xml.Schema.Linq.dll!Xml.Schema.Linq.XTypedServices.ToXTypedElement(System.Xml.Linq.XElement xe = <References>
  <ReferenceID>0</ReferenceID>
  <ReferenceType>string</ReferenceType>
  <PermitNumber>string</PermitNumber>
</References>, Xml.Schema.Linq.ILinqToXsdTypeManager typeManager = {LinqToXsdTypeManager}, System.Type t = {Name = "Base" FullName = "Base"}) 

Anybody know how to make this work?

We're still stuck in the dot net 3.5 version, can anybody verify if this works in the dot net 4.0 version?

Or do I need to go hack it in myself?

Thanks,

James.