Consider the following simple schema:
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="MyRoot">
<xs:complexType>
<xs:sequence>
<xs:group ref="MyChoice" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:group name="MyChoice">
<xs:choice>
<xs:element name="a" type="xs:string"/>
<xs:element name="b" type="xs:string"/>
<xs:element name="c" type="xs:string"/>
</xs:choice>
</xs:group>
</xs:schema>
When turning this into C# code with xsd.exe (VS2017), I get the following output:
public partial class MyRoot {
private string[] aField;
private string[] bField;
private string[] cField;
// ... omitted for brevity ...
}
This code has a major problem: in the XSD/XML all of the sub-elements (a, b and c) were ordered.
This order is now lost in the C# class, since there are three different arrays for each of the sub elements.
Is xsd.exe doing it wrong? Or am I using it wrong? Or is the .xsd file flawed?
Related
I have a sample to read a xml schema set for a xml file which contains different namespaces. For this i can get different schema for each namespace as i explained below.
Sample File:
<?xml version="1.0" encoding="utf-8"?>
<data xmlns:d="http://sampleschema/dataservices" xmlns:m="http://sampleschema/dataservices/metadata">
<content>
<m:properties>
<d:CustomerID>ALFKI</d:CustomerID>
<d:CompanyName>Alfreds Futterkiste</d:CompanyName>
</m:properties>
</content>
</data>
Sample Code to get XML Schema Set:
strFileName = #"C:\Sample\Sample.xml";
XmlReader reader = XmlReader.Create(strFileName);
XmlSchemaInference schema = new XmlSchemaInference();
XmlSchemaSet schemaSet = schema.InferSchema(reader);
It gives three different types of schemas while using the above code. But my requirement will be i need a single schema for the entire xml file which contain any number of namespaces in it. I have checked with possibilities of codes in msdn and stack overflow. I can't find any proper solution for this.
The expected schema output will be like below.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="data">
<xs:complexType>
<xs:sequence>
<xs:element name="content">
<xs:complexType>
<xs:sequence>
<xs:element name="m:properties">
<xs:complexType>
<xs:sequence>
<xs:element name="d:CustomerID" type="xs:string"></xs:element>
<xs:element name="d:CompanyName" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="xmlns:d" type="xs:string"></xs:attribute>
<xs:attribute name="xmlns:m" type="xs:string"></xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
Any one can help to achieve this requirement.
Thanks in advance.
Try something like this :
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:m="http://www.w3.org/2001/XMLSchema" xmlns:d="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="data">
<xs:complexType>
<xs:sequence>
<xs:element name="content">
<m:complexType>
<m:sequence>
<m:element name="properties">
<d:complexType>
<d:sequence>
<d:element name="CustomerID" type="xs:string"></d:element>
<d:element name="CompanyName" type="xs:string"></d:element>
</d:sequence>
</d:complexType>
</m:element>
</m:sequence>
</m:complexType>
</xs:element>
</xs:sequence>
<d:attribute name="xmlns_d" type="d:string"></d:attribute>
<m:attribute name="xmlns_m" type="d:string"></m:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
I hope I am correctly phrasing my problem. When we run the xsd tool on our xsd to create classes, the code is not exactly representing the xsd on one section. It is like this:
XSD: 'BaliseGroups' => Collection of 'BaliseGroup' => Collection of 'Balise'
Code: 'BaliseGroups' => Collection of type 'Balise' named 'BaliseGroup'...
<xs:element name="BaliseGroups">
<xs:annotation>
<xs:documentation>Een verzameling balisegroepen</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="BaliseGroup" type="tBaliseGroup"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="tBaliseGroup">
<xs:annotation>
<xs:documentation>Een balisegroep, </xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="Balise" type="tBalise" minOccurs="1" maxOccurs="8"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="tBalise">
<xs:annotation>
<xs:documentation>Type voor een balise</xs:documentation>
</xs:annotation>
<xs:complexContent>
<xs:extension base="tTrackAsset"/>
</xs:complexContent>
</xs:complexType>
Code
public partial class BaliseGroups
{
private tBalise[] baliseGroupField;
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("Balise", IsNullable = false)]
public tBalise[] BaliseGroup
{
get
{
return this.baliseGroupField;
}
set
{
this.baliseGroupField = value;
}
}
}
As you can see in the generated C# code block it creates a Property BaliseGroup of type Balise[]. This should be of type tBaliseGroup[].
I have a conjecture that there is something wrong with the xsd, but I cannot figure out what..
I have solved my problem. By annotating in the xsd that 'BaliseGroup' has a maxOccurs of 'unbounded' it creates the collection of 'BaliseGroup' in 'BaliseGroups'. Here is the change:
<xs:element name="BaliseGroups">
<xs:annotation>
<xs:documentation>Een verzameling balisegroepen</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="BaliseGroup" type="tBaliseGroup" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
So, I have the following data contract:
[DataContract(Namespace = "http://abc/Services/Data")]
public abstract class AbcObject
{
[DataMember]
[XmlAnyElement]
public XmlElement[] Any { get; set; }
}
My expectation is to see the following corresponding xs:complexType element in the generated wsdl:
<xs:complexType name="AbcObject">
<xs:sequence>
<xsd:any minOccurs="0"/>
</xs:sequence>
</xs:complexType>
However, what I actually see is:
<xs:complexType name="AbcObject">
<xs:sequence>
<xs:element name="Any" type="q1:ArrayOfXmlElement" nillable="true" minOccurs="0" xmlns:q1="http://schemas.datacontract.org/2004/07/System.Xml"/>
</xs:sequence>
</xs:complexType>
So, this is not what I want, but I am kind of puzzled how to get the xsd:any generated for me.
Any ideas?
EDIT 1
As per jamiemeyer advice I have changed the DFObject.Any property to be of type XmlAttribute[]. Here is the result:
<xs:complexType name="DFObject">
<xs:sequence>
<xs:element name="Any" type="q1:ArrayOfArrayOfanyType" nillable="true" minOccurs="0" xmlns:q1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</xs:sequence>
</xs:complexType>
Although the result is different, it is still not xsd:any.
I have been provided the following XML request as a model to follow along with the WSDL.
<xs:complexType name="commonInput">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="propertyList" nillable="true" type="tns:commonProperty" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="commonProperty">
<xs:sequence>
<xs:element minOccurs="0" name="context" type="xs:string" />
<xs:element minOccurs="0" name="name" type="xs:string" />
<xs:element minOccurs="0" name="value" type="xs:string" />
</xs:sequence>
</xs:complexType>
I am expected to create a response in code using these types to create something similar to the following
<commonInput>
<loginId></loginId>
<propertyList>
<context></context>
<name></name>
<value></value>
</propertyList>
<propertyList>
<context></context>
<name></name>
<value></value>
</propertyList>
</commonInput>
The issue I'm encountering is that I cannot figure out how to create this structure in code since the commonInput.propertyList is not an array or list, it is simply a class.
How can I create multiple instances of propertyList within the commonInput?
Your class commonInput has an attribute called propertyList, which is a sequence of entities of type commonProperty. Note the <xs:sequence> tags that enclose its definition.
So you should be able to use something like:
private List<CommonProperty> propertyList = new ArrayList<CommonProperty>();
I'm not exactly sure what translation you use from XML to your "class".
We use Jaxb to translate between XML and java classes automatically.
In response to your comment, I will try to clarify with an example:
Our WSDL defines:
<s:complexType name="ArrayOfTEKLeverancierObj">
<s:sequence>
<s:element minOccurs="0" maxOccurs="unbounded" name="TEKLeverancierObj"
nillable="true" type="tns:TEKLeverancierObj" />
</s:sequence>
</s:complexType>
And in our java class this translates to:
public class ArrayOfTEKLeverancierObj {
#XmlElement(name = "TEKLeverancierObj", nillable = true)
protected List<TEKLeverancierObj> tekLeverancierObj;
I have an xml document that contains some html.
<begin-line>
<verse-num>6</verse-num>a mixed people<footnote id="f2">
Or <i>a foreign people</i>; Hebrew <i>a bastard</i>
</footnote> shall dwell in Ashdod,
</begin-line>
The verse-num element is the only element I wan't validated, the rest I want valideted to one large group of a string type, which can hold html, and also sometimes some more xml (like footnote).
Here is the schema I have right now which doesn't do the trick.
<xs:element maxOccurs="unbounded" name="begin-line">
<xs:complexType mixed="true">
<xs:sequence minOccurs="0">
<xs:choice maxOccurs="unbounded">
<xs:element name="verse-num">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:unsignedByte">
<xs:attribute name="begin-chapter" type="xs:unsignedByte" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:sequence>
<xs:attribute name="class" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
I am using XSD.exe to generate a class that I can deserialize this junk into.
It is generating a begin-line object with a verse-num type below it, and also an array of text, which are split by the html/xml tags inside of .
What I need is an xsd that can be used by XSD.exe to generate a begin-line class that will give me a verse-num type, and then one string property that will contain the rest of the content (including text, i's, b's, footnotes, xml/html).
I did some research and it seems like processContents will do the trick, but I can't figure out where to put it.
When it comes down to it, I want to program against the object created by the XSD.exe like this.
var beginLine = new crosswaybiblePassageVerseunitBeginline();
Console.WriteLine((beginLine.Items[0] as crosswaybiblePassageVerseunitBeginlineVersenum).Value);
Console.Write(beginLine.Text);
or maybe even...
var beginLine = new crosswaybiblePassageVerseunitBeginline();
Console.WriteLine(beginLine.Versenum.Value);
Console.Write(beginLine.Text);
I'm not sure how to setup the schema such that it'll provide nice output from XSD.exe but you can specify "any number of elements with any name" in the output using a type with the definition:
<xs:complexType name="AnyChildren">
<xs:sequence>
<xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded" namespace="##any"/>
</xs:sequence>
<xs:anyAttribute />
</xs:complexType>
For example to validate:
<Module>
<Title>Hello World</Title>
<ProviderType>xyz</ProviderType>
<Content />
<MoreContent />
</Module>
You could use:
<xs:complexType name="Module">
<xs:sequence>
<xs:element name="Title" type="xs:string" maxOccurs="1" />
<xs:element name="ProviderType" type="xs:string" minOccurs="1" nillable="false" />
<xs:any processContents="skip" minOccurs="0" maxOccurs="unbounded" namespace="##any"/>
</xs:sequence>
<xs:anyAttribute />
</xs:complexType>