views:

102

answers:

1

I have a problem that can perhaps be solved in a more efficient or clean way, than my current solution.

Over the past days I have gotten a fairly good understanding of how Xml serialization can be controlled via attributes, but one part of the Xml structure is so obscure, that I have not been able to find a smart solution.

I have been handed an Xml schema, which cannot be altered, and to which I must create a C# class.

The code that bugs me is the following:

<xs:complexType name="dataRefType">
    <xs:sequence>
        <xs:element name="Data" type="DataType"/>
        <xs:sequence minOccurs="0" maxOccurs="unbounded">
            <xs:element name="Separator" type="xs:string"/>
            <xs:element name="Data" type="DataType"/>
        </xs:sequence>
    </xs:sequence>
</xs:complexType>
<xs:complexType name="DataType">
    <xs:choice>
        <xs:sequence>
            <xs:element name="DataOwner" type="xs:string"/>
            <xs:element name="Name" type="xs:string"/>
        </xs:sequence>
        <xs:element name="XPath" type="xs:string"/>
    </xs:choice>
</xs:complexType>

My first idea was to manage this by having a generic list, that could be one of three types of classes, which has worked so far, but the problem here is the ambiguous name "Data".

Here is the code I originally made:

[XmlRoot("DataRef")]
public class DataRef
{
    protected List<DataRoot> m_Data = new List<DataRoot>(1);

    [XmlElement(typeof(DataUserField))]
    [XmlElement(typeof(DataMasterField))]
    [XmlElement(typeof(DataSeparator))]
    public List<DataRoot> Data { get { return m_Data; } set { m_Data = value; } }
}

public abstract class DataRoot { }

[XmlRoot("Data")]
public class DataUserField : DataRoot
{
    protected string m_DataOwner;
    protected string m_Name;

    [XmlElement("DataOwner")]
    public string DataOwner { get { return m_DataOwner; } set { m_DataOwner = value; } }
    [XmlElement("Name")]
    public string Name { get { return m_Name; } set { m_Name = value; } }
}

[XmlRoot("Data")]
public class DataMasterField : DataRoot
{
    protected string m_XPath;

    [XmlElement("XPath")]
    public string XPath { get { return m_XPath; } set { m_XPath = value; } }
}

[XmlRoot("Separator")]
public class DataSeparator : DataRoot
{
    protected string m_Text = "";

    [XmlText()]
    public string Text { get { return m_Text; } set { m_Text = value; } }
}

This unfortunately did not work, and I assume it is because of the ambiguous element name "Data", since the error-message is pretty vague, but does have a reference to the line-number of the error.

As I said in the beginning, I already have a solution, but it is far from elegant, and definitely not in .Net spirit, which is why I would greatly appreciate any help.

My solution to those interested involves one class to represent "DataType" with one field for the type and three other fields for "DataOwner", "Name" and "XPath", where the type is an enum that can be either "DataUserField" or "DataMasterField".

Sorry for the long post, but I felt it would be better to have some proper code samples, please say if you need more info.

A: 

Have a look at the XSD.EXE tool, it will generate C# classes for you from an XSD schema.

It should be installed already on your machine (C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\xsd.exe for .NET Framework 3.5).

There's a tutorial to use it on codeproject.com

Patrick McDonald
Thank you for that note, but I prefer a bit more control over the serialization process...BTW: I already tried XSD.exe and it's solution was to have one class for "Data" containing two string arrays, one with the typename and one with the content.This I feel, and please correct me if you think I am wrong, is not really the .Net way...
reSPAWNed