Alternatives to LINQ to XSD for complex schemas that fail to compile?

May 30, 2011 at 7:19 AM
Edited May 30, 2011 at 7:19 AM

What is the best alternative for an XSD to Object project that works well with large complex schemas that have numerous choices? I ask because LinqToXSD failed to compile my schema.

May 31, 2011 at 8:45 AM

We used XMLSpy Enterprise edition before we used Linq2Xsd.

Post your Xsd or a link to it and I can test whether our copy of XMLSpy generates code without errors.

Or you can download the 30 day trial from Altova.

We still use XMLSpy for Xsd design but I never really like the code it generated, especially as it was a manual process.

You have to repeat it each time and copy/paste the generated code files into your solution.

Regards,

J1M.

May 31, 2011 at 8:50 AM

The schema is used for the XML API for a product called Kronos (makers of a time and attendence solution)

Link to the Xsd http://www.mediafire.com/?ek3o91p4e0hqqao

Most Xsd to source code solutions fail to pickup the choice available on the Kronos_WFC type. Which is crucial. Another one (LiquidXML) worked great until it was time to serialize data back into objects.

I hope you have success with it!

May 31, 2011 at 9:23 AM

Well, it generates code OK, which compiles.

That choice is only ever going to get you a Transaction, Response and Request properties, there won't be any kind of enforced "choice" in the code.

You will be able to use all three and it just blindly generates bad non-conformant Xml.

Same as Linq2Xsd I guess, and that doesn't even generate sequence elements in the right order!

The following code:

 

            Kronos_XMLAPI_6_22 doc = Kronos_XMLAPI_6_2.Kronos_XMLAPI_6_22.CreateDocument();
            Kronos_WFCType root = doc.Kronos_WFC.Append();

            var response = root.Response.Append();

            response.Message.Append().Value = "Hello World!";
            response.Sequence.Append().Value = "Sequence";
            response.Status.Append().Value = "Status";
            response.TransactionSequence.Append().Value = "Sequence";

            doc.SaveToFile("test.xml", true);

 

Produces the following Xml:

<?xml version="1.0" encoding="utf-8"?>
<Kronos_WFC>
	<Response>
		<Message>Hello World!</Message>
		<Sequence>Sequence</Sequence>
		<Status>Status</Status>
		<TransactionSequence>Sequence</TransactionSequence>
	</Response>
</Kronos_WFC>

Which is wrong becase the Version attribute is missing and Altova does not generate a strong typed property for Kronos_WFC.Version.

No idea why, maybe I juyst don't know how to use it properly. The code wrappers it produces are pretty eye watering compared to Linq2Xsd, so we stopped using one as soon as we found the other.

Recommend you grab the demo and try it for yourself. It's not cheap though :(

Hope that helps,

J1M.

May 31, 2011 at 9:34 AM

Thanks for checking that out for me. I really appreciate your time. :) I will download the Altova trial and see how I go.

Its a shame that LinqToXsd fails to compile it and Xsd2code is hopeless at dealing with the "choice".

You should download the trial of Liquid XML and check its code generation out. Have a read of this: http://www.liquid-technologies.com/XmlDataBinding/Xml-Schema-To-Cs.aspx. Its proprietary but it does a reasonable job, but fails when you try to deserialize.

I am going to look into why LinqToXsd fails and try to debug it.

Can I ask one more question: What do you recommend I do if Altova XML Spy cannot deserialize correctly?

May 31, 2011 at 10:12 AM

Just for an example this is what needs to be deserialized back from the web service:

<?xml version="1.0" encoding="UTF-8"?>
<Kronos_WFC TimeStamp="10/01/2010 1:23PM GMT+10:00" WFCVersion="6.2.2.364" version="1.0">

<Response Status="Success" Action="AddOnly"></Response>

</Kronos_WFC>

May 31, 2011 at 10:29 AM
jeremychild wrote:
Can I ask one more question: What do you recommend I do if Altova XML Spy cannot deserialize correctly?

Take the revolver from your drawer? ;-)

I've had a look at the Xsd in Linq2Xsd. It's choking on the names of the simple types.

Looks like you should get some milage out of renaming the types and the types/elements that point to it.

This *should* create identical Xml files as those names don't appear in the finished Xml.

I had a brief stab at changing the names and it does fix the Linq2Xsd errors.

I did this:

	<xsd:simpleType name="KDate">
		<xsd:restriction base="xsd:string"/>
	</xsd:simpleType>

And this using search and replace:

			<xsd:element name="EffectiveDate" type="KDate" minOccurs="0"/>

And that got rid of the first block of errors in Linq2Xsd, I tried a few more and it doesn seem to work.

All you have to do then is all the rest. And hope there are no more problems after that.

As long as you have a tool capable of validating the generated Xml against the schema you can be confident the Xml you're generating is good.

J1M.

May 31, 2011 at 10:42 AM

Thankyou. I will add the K suffix to all the simple types and see how it goes in Linq2XSD.

At the moment I have removed safety from the revolver... seems I might just have to give up.

Sep 8, 2011 at 1:54 PM
Edited Sep 8, 2011 at 1:55 PM

this is a poorly designed XSD for the purposes of being an API that could be coded against... most people are still not aware that XSD is _not_ an object designer but its a specification that determines the structure of an XML file...

straight off the bat we have: 

            <xsd:choice maxOccurs="unbounded" minOccurs="0">
                <xsd:element name="Transaction" type="TransactionType"/>
                <xsd:element name="Response" type="ResponseType"/>
                <xsd:element name="Request" type="RequestType"/>
            </xsd:choice>

the xsd:choice element is problematic to translate to code as its specified with minOccurs=0 

if you are an XSD compiler and you need to generate code that represents this reality you don;t have much other choice but to generate stubs for the Transaction,Response and/or Request classes and populate them if and when the data for them is present. This has the ugly side effect that if you are the consumer of this atrocity you will need to implement null checking a lot more than you really should.

See section 4.2 of this document