views:

321

answers:

3

I'm working on a project that has to connect to some ancient webservices that pack some hierarchical data for requests and responses into single strings of hierarchical XML.

I've been using xsd.exe to generate XSDs from sample request and response XML fragments, modifying them where necessary to be the best possible definition, and using xsd.exe again to generate C# objects. The managers that call the webservices can then take those strongly-typed request objects as parameters, serialize them to strings in order to make the calls, get the responses back as strings, deserialize them into the strongly-typed response objects and return those.

If I have, say, a list of strings, I can have a valid XSD that considers it a complex type of an unbounded xs:choice of xs:string elements, and then it will deserialize simply to a string array, which is nice and simple to deal with. The annoying problem is that for some reason, there doesn't seem to be any way to get it to call the string array anything other than "Items". No matter what I add to the schema, I can't get xsd.exe to write any other name.

Here's an example XSD schema:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="AccountStatusRequest" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="AccountStatusRequest">
        <xs:complexType>
            <xs:choice minOccurs="0" maxOccurs="unbounded" id="AccountRowIDs">
                <xs:element nillable="true" type="xs:string" id="AccountRowID" name="AccountRowID"/>
            </xs:choice>
        </xs:complexType>
    </xs:element>
</xs:schema>

And the resulting class:

public partial class AccountStatusRequest {

    private string[] itemsField;

    [System.Xml.Serialization.XmlElementAttribute("AccountRowID", Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=true)]
    public string[] Items {
        get {
            return this.itemsField;
        }
        set {
            this.itemsField = value;
        }
    }
}

I've tried adding pretty much every msdata: attribute in intellisense to both the choice and the inner element, and nothing makes a difference.

Just for the sake of argument, I added a couple extra similar choices to that complexType, to see if that would force it to use a name for the string arrays, but instead it gave me Items, Items1, Items2...

I really don't want it to have to be an array of its own type that only holds a string, but I also really don't want to leave it called "Items", without xml comments (does anyone know how to add THOSE to an xsd?), when it should have a more descriptive name. And I definitely can't just change it manually as the desired workflow whenever the webservice schemas change is to change the XSDs and then re-generate the classes from them.

This seems like another one of those things xsd.exe should support. Is there something I'm missing? Should I take a different approach somehow? Or is there an alternative tool I can use for this instead that's less lame?

A: 

I'm fairly sure that is a limitation of xsd.exe; you can get custom results in the other direction (class => xml/xsd), but that doesn't help you much. Sorry.

Marc Gravell
+2  A: 

Try changing choice to sequence, and put the min/max occurs in the AccountRowID element...

Sorry not sure how I missed this answer - it worked for me +1
RobS
A: 

Edit: sorry I missed the previous answer somehow - it worked for me - here's the schema I used and the result. My original answers might also be appropriate too.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="AccountStatusRequest" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="AccountStatusRequest" msdata:ColumnName="AccountList">
        <xs:complexType>
            <xs:sequence minOccurs="0" maxOccurs="unbounded" id="AccountRowIDs">
              <xs:element nillable="true" type="xs:string" id="AccountRowID" name="AccountRowID"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>  
</xs:schema>

public partial class AccountStatusRequest {

    private string[] accountRowIDField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("AccountRowID", Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=true)]
    public string[] AccountRowID {
        get {
            return this.accountRowIDField;
        }
        set {
            this.accountRowIDField = value;
        }
    }
}

Hi there, I changed the schema somewhat, substituting the choice with a list wrapped by a simpleType and an attribute, which produced the desired output (a named string array). However, I'm not sure if the altered schema is appropriate for what you are doing?

Here's the modified schema:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="AccountStatusRequest" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="AccountStatusRequest" msdata:ColumnName="AccountList">
        <xs:complexType>
          <xs:attribute name="AccountRowIDs">
            <xs:simpleType id="AccountRowID"  >
              <xs:list itemType="xs:string">                
              </xs:list>
            </xs:simpleType>       
          </xs:attribute>
        </xs:complexType>
    </xs:element>  
</xs:schema>

..and the output after running it with xsd.exe:

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public partial class AccountStatusRequest {

    private string[] accountRowIDsField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string[] AccountRowIDs {
        get {
            return this.accountRowIDsField;
        }
        set {
            this.accountRowIDsField = value;
        }
    }
}
RobS