Handle two XML files with one schema file - xsd

I have a short question to my XSD Problem.
I have created an test.xsd file how should handle 2 XML types.
One for my database and one for an third party application.
It works great whether I use the database XML files, but in the third Party software the XML tag is on another position. Let me explain:
Database XML summary:
<tempData> 123456 </tempData>
<DataSet> 505 </DataSet>
third party software xml summary:
<DataSet> 505 </DataSet>
<tempData> 123456 </tempData>
XSD summary:
<xs:complexType>
<xs:sequence>
<xs:element name="Data" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element ref="tempData" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="DataSet" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="tempData" />
<xs:element ref="DataSet" />
</xs:choice>
</xs:complexType>
</xs:element>
When I would like to validate these two different XML files with my XSD file for the database XML file it works and for the third party XML file with the inverted tags it will not validate.
How can I handle these two different arrangements?

below is a solution that will allow both 'DataSet' and 'tempData' to be present in the 'Data' element, either both at the same time (in any order), one or the other alone, or neither of them (empty 'Data' element).
If you wish to force either one to be present, change the minOccurs to '1'.
You cannot have more than one of each of these elements within the 'Data' element when using 'xs:all' - either minimum 0 or 1.
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Data">
<xs:complexType>
<xs:all>
<xs:element name="tempData" minOccurs="0" />
<xs:element name="DataSet" minOccurs="0" />
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
Try it with:
<Data>
<DataSet> 505 </DataSet>
<tempData> 123456 </tempData>
</Data>
<Data>
<tempData> 123456 </tempData>
<DataSet> 505 </DataSet>
</Data>
<Data>
<DataSet> 505 </DataSet>
</Data>
<Data>
<tempData> 123456 </tempData>
</Data>
<Data>
</Data>
And your XML will be valid

As Martin has mentioned, this is an XML Schema question, not XSLT.
You need the xs:all element, so soemthing like:
<xs:all>
<xs:element ref="tempData" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="DataSet" minOccurs="0" maxOccurs="unbounded" />
</xs:all>
Do you really want both elements to be optional?

Related

XSD circular imports

Is it valid to have two xsd's import each other?
For example, the first one is 'MyService.xsd=48 and it looks like:
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema xmlns:tns="http://documentation" xmlns:ns1="http://documentHistory" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified" version="1.0" targetNamespace="http://documentation">
<xs:import namespace="http://documentHistory" schemaLocation="MyService.xsd=49" />
<xs:complexType name="item">
<xs:sequence>
<xs:element name="internalId" type="xs:long" minOccurs="0" />
<xs:element name="readOnly" type="xs:boolean" minOccurs="0" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="data">
<xs:sequence>
<xs:element name="histories" type="ns1:history" nillable="true" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:schema>
The second xsd is MyService.xsd=49 and looks like:
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema xmlns:tns="http://documentHistory" xmlns:ns1="http://documentation" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified" version="1.0" targetNamespace="http://documentHistory">
<xs:import namespace="http://documentation" schemaLocation="MyService.xsd=48" />
<xs:complexType name="history">
<xs:complexContent>
<xs:extension base="ns1:item">
<xs:sequence>
<xs:element name="dateReceived" type="xs:dateTime" minOccurs="0" />
<xs:element name="dateSent" type="xs:dateTime" minOccurs="0" />
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Notice that the first one imports the second one and the second one imports the first one. I have an issue that I'm trying to track down and I don't know if this is part of the problem or not. The issue I'm trying to solve has to do with TCL not seeming to parse my wsdl correctly. After TCL parses the wsdl into a dict, the 'history' object doesn't have the properties from the 'item' object, even though the xsd shows that history should extend from item.
The question is: is it valid for two xsd's to import each other or does this look like a problem?
Also, I already looked at this post XSD circular import but found the answer difficult to understand. Any help / insight would be greatly appreciated. Thanks!

jaxb generated class for xsd:group

I have the following xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element ref="age"/>
<xs:group ref="gp.contacts"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:group name="gp.contacts">
<xs:sequence>
<xs:element ref="name" maxOccurs="unbounded"/>
<xs:element ref="phone" maxOccurs="unbounded"/>
<xs:element ref="address" maxOccurs="unbounded"/>
</xs:sequence>
</xs:group>
</xs:schema>
</xs:schema>
Then I'm using jaxb when I create xml, the output is
<root>
<age>25to35</age>
<contacts>
<name>...</name>
<name>...</name>
<name>...</name>
<phone>...</phone>
<phone>...</phone>
<phone>...</phone>
<address>..</address>
<address>..</address>
<address>..</address>
</contacts>
</root>
But I want the output to be like this
<root>
<age>25to35</age>
<contacts>
<name>...</name>
<phone>...</phone>
<address>..</address>
<name>...</name>
<phone>...</phone>
<address>..</address>
<name>...</name>
<phone>...</phone>
<address>..</address>
</contacts>
</root>
Can someone please tell me if this output can be achieved through modifying the xsd or jaxb or by any other way.
If you want to allow unbounded sequences, each containing one (name, phone, address), in that order, you need to remove it from the containing elements (which will now allow and require only one of each, which is the default):
<xs:group name="gp.contacts">
<xs:sequence>
<xs:element name="name"/>
<xs:element name="phone"/>
<xs:element name="address"/>
</xs:sequence>
</xs:group>
Then you need to declare that the sequence is unbounded. Since you declared a group, you do that when you reference it:
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element ref="age"/>
<xs:group ref="gp.contacts" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
This might not solve your problem yet. You said that JAXB was generating the XML you included in your question with the <contacts> element. Your schema does not validate that. I assume you are wrapping that in JAXB (you didn't show your code), but if you can edit the schema it's better to do so since your XML will validate against it). The schema as is actually validates this:
<root>
<age>25to35</age>
<name>...</name>
<name>...</name>
...
<address>..</address> ...
<phone>...</phone>
...
</root>
With the modifications, now it validates this:
<root>
<age>25to35</age>
<name>...</name>
<phone>...</phone>
<address>..</address>
<name>...</name>
<phone>...</phone>
<address>..</address>
<name>...</name>
<phone>...</phone>
<address>..</address>
...
</root>
For it to validate the XML you want it to generate, with the <name>, <phone> and <address> sequences nested in <contacts>, you need to add a declaration for the <contacts> element in XML Schema, and reference the group from inside it:
<xs:element name="root">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="age" type="xs:string"/>
<xs:element name="contacts">
<xs:complexType>
<xs:group ref="gp.contacts" maxOccurs="unbounded"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
Your schema also has doubled <schema> root elements (I assumed that was a cut-and-paste typo.)
If you fix these problems, you can use the schema to generate classes for JAXB that will create XML the instances you want.

XML Schema: require an element to be present when another is present

My Schema allows a specific element to be optional, but when I encounter a different also optional element later on in the file, I need the previous one to be present. How can I ensure this via XSD?
Example:
<settings>
<file name="narf.txt"/>
<metafile name="narf.meta"/>
<filtermeta>true</filtermeta>
</settings>
should be valid,
<settings>
<file name="narf.txt"/>
<metafile name="narf.meta"/>
</settings>
and
<settings>
<file name="narf.txt"/>
</settings>
should be valid too,
<settings>
<file name="narf.txt"/>
<filtermeta>true</filtermeta>
</settings>
should not be valid.
Try the following schema definition:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="settings">
<xs:complexType>
<xs:sequence>
<xs:element name="file">
<xs:complexType>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:sequence minOccurs="0">
<xs:element name="metafile">
<xs:complexType>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" name="filtermeta" type="xs:string"/>
</xs:sequence>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
I've run your first three examples against this schema using xmllint and they validate correctly. The fourth example fails with:
cvc-complex-type.2.4.a: Invalid content was found starting with element 'filtermeta'. One of '{metafile}' is expected.
as expected.
You could have filtermeta as an optional attribute to the metafile element.

XSD: specify a choice must have at least one from a list but no more than one of each

This has been driving me mad for hours. I've read every relevant XSD question on SO and the rest of the Internet it seems and still the answer eludes me.
I need an XML schema that requires at least one of list of elements be present, but each element may appear only 0 or 1 times.
This is similar to this question:
XML schema construct for "any one or more of these elements but must be at least one"
but I was unable to constrain the upper limit: I am apparently using maxOccursincorrectly.
Here's where I left off with my 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="Selects">
<xs:sequence minOccurs="2" maxOccurs="4">
<xs:choice>
<xs:element name="aaa" minOccurs="1" maxOccurs="1"/>
<xs:element name="bbb" minOccurs="1" maxOccurs="1"/>
<xs:element name="ccc" minOccurs="1" maxOccurs="1"/>
<xs:element name="ddd" minOccurs="1" maxOccurs="1"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
<xs:element name="baseElement">
<xs:complexType>
<xs:sequence>
<xs:element name="MyChoice" type="Selects"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
I've tried the minOccurs and maxOccurs on the choice and the element with no luck. Here is XML that validates, though I don't want it to:
<?xml version="1.0" encoding="UTF-8"?>
<baseElement xsi:noNamespaceSchemaLocation="myTest.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MyChoice>
<ddd/>
<ddd/>
</MyChoice>
</baseElement>
Here's an example of what I would like, if possible:
<?xml version="1.0" encoding="UTF-8"?>
<baseElement xsi:noNamespaceSchemaLocation="myTest.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MyChoice>
<ddd/>
<aaa/>
<ccc/>
</MyChoice>
</baseElement>
I would like it to complain about the multiple ddd elements but allow any or all of the others in any order. I get an error if I only have one element under MyChoice so at least something works.
What am I doing wrong? How do I prevent multiple of the same element from validating?
UPDATE
This was my solution (from comments on answer below):
Actually, xs:all did the trick. I swapped the choice for all and added minOccurs="0" maxOccurs="1" to each element. With xs:all, minOccurs must be either 0 or 1 and maxOccurs must be 1. Thanks for your help - I'm good to go now!
Just move the <xs:sequence minOccurs="2" maxOccurs="4"> from around the choice to the point where you want to use it further down. (you can also remove the min/max occurs = 1 as this is what xs:choice does)
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="Selects">
<xs:choice>
<xs:element name="aaa" />
<xs:element name="bbb" />
<xs:element name="ccc" />
<xs:element name="ddd" />
</xs:choice>
</xs:complexType>
<xs:element name="baseElement">
<xs:complexType>
<xs:sequence minOccurs="2" maxOccurs="4">
<xs:element name="MyChoice" type="Selects" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
This validates the following:
<baseElement xsi:noNamespaceSchemaLocation="myTest.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MyChoice>
<bbb></bbb>
</MyChoice>
<MyChoice>
<ccc></ccc>
</MyChoice>
</baseElement>
UPDATE
I think you are reaching the limit of what you can achieve with XSD. I can't see any way you can do this other than by defining a "version" of the MyChoice type for every single combination possible (which will then need different names MyChoice1, MyChoice2 etc)
You can also use xs:all
<xs:complexType name="Selects">
<xs:all minOccurs=2 maxOccurs=4>
<xs:element name="aaa" />
<xs:element name="bbb" />
<xs:element name="ccc" />
<xs:element name="ddd" />
</xs:all>
</xs:complexType>
but this will not prevent you from having four <ddd/>'s

Question about xsd. Elements inside complex type must be allowed in any order

If you look at the following xsd fragment you can conclude that the corresponding xml will first contain cars followed by busses eg:
car,car,bus,bus
HOWEVER I want the xml to be able to contain
car,bus,car,bus
What change do I need to make in the xsd below in order to achieve this?
<xs:element name="body">
<xs:complexType>
<xs:sequence>
<xs:element name="session" type="tns:session" />
<xs:element minOccurs="0" maxOccurs="unbounded" name="car" type="tns:car" />
<xs:element minOccurs="0" maxOccurs="unbounded" name="bus" type="tns:bus" />
</xs:sequence>
</xs:complexType>
</xs:element>
It's a bit cumbersome, but you might achieve what you're looking for like this:
create a <xs:choice> element with your car and bus elements inside; this defines that one of the contained elements can be used
make sure to have the attribtues minOccurs=1 and maxOccurs=unbounded on that <xs:choice> - this gives you any number of either car or bus elements - any number, any combination
So your XML schema would look something like this (I added some stuff just to be able to generate a sample XML and verify it works - tweak as needed):
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="body">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element minOccurs="0" maxOccurs="unbounded" name="car" type="CarType" />
<xs:element minOccurs="0" maxOccurs="unbounded" name="bus" type="BusType" />
</xs:choice>
</xs:complexType>
</xs:element>
<xs:complexType name="CarType">
<xs:sequence>
<xs:element name="Maker" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="BusType">
<xs:sequence>
<xs:element name="Maker" type="xs:string" />
<xs:element name="Capacity" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:schema>
use <xs:any> insted of <xs:sequence>

Resources