Recursion in an XML schema? - xsd

I need to create an XML schema that validates a tree structure of an XML document. I don't know exactly the occurrences or depth level of the tree.
XML example:
<?xml version="1.0" encoding="utf-8"?>
<node>
<attribute/>
<node>
<attribute/>
<node/>
</node>
</node>
Which is the best way to validate it? Recursion?

if you need a recursive type declaration, here is an example that might help:
<xs:schema id="XMLSchema1"
targetNamespace="http://tempuri.org/XMLSchema1.xsd"
elementFormDefault="qualified"
xmlns="http://tempuri.org/XMLSchema1.xsd"
xmlns:mstns="http://tempuri.org/XMLSchema1.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:element name="node" type="nodeType"></xs:element>
<xs:complexType name="nodeType">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="node" type="nodeType"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
As you can see, this defines a recursive schema with only one node named "node" which can be as deep as desired.

XSD does indeed allow for recursion of elements. Here is a sample for you
<xsd:element name="section">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="title"/>
<xsd:element ref="para" maxOccurs="unbounded"/>
<xsd:element ref="section" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
As you can see the section element contains a child element that is of type section.

The other solutions work great for making root elements recursive. However, in order to make a non-root element recursive without turning it into a valid root element in the process, a slightly different approach is needed.
Let's say you want to define an XML message format for exchanging structured data between nodes in a distributed application. It contains the following elements:
<message> - the root element;
<from> - the message's origin;
<to> - the message's destination;
<type> - the data structure type encoded in the message;
<data> - the data contained in the message.
In order to support complex data types, <data> is a recursive element. This makes possible to write messages as below, for sending e.g. a geometry_msgs/TwistStamped message to a flying drone specifying its linear and angular (i.e. rotating) speeds:
<?xml version="1.0" encoding="utf-8"?>
<message xmlns="https://stackoverflow.com/message/1.0.0">
<from>controller:8080</from>
<to>drone:8080</to>
<type>geometry_msgs/TwistStamped</type>
<data name="header">
<data name="seq">0</data>
<data name="stamp">
<data name="sec">1</data>
<data name="nsec">0</data>
</data>
<data name="frame_id">base_link</data>
</data>
<data name="twist">
<data name="linear">
<data name="x">1.0</data>
<data name="y">0</data>
<data name="z">1.0</data>
</data>
<data name="angular">
<data name="x">0.3</data>
<data name="y">0</data>
<data name="z">0</data>
</data>
</data>
</message>
We can easily write an XML schema to validate this format:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="https://stackoverflow.com/message/1.0.0"
elementFormDefault="qualified"
xmlns="https://stackoverflow.com/message/1.0.0"
>
<xs:element name="data">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element ref="data" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="message">
<xs:complexType>
<xs:sequence>
<xs:element name="from" type="xs:string"/>
<xs:element name="to" type="xs:string"/>
<xs:element name="type" type="xs:string"/>
<xs:element ref="data" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
The problem with the schema above is that it makes <data> a root element, which means it also validates the document below:
<?xml version="1.0" encoding="utf-8"?>
<data xmlns="https://stackoverflow.com/message/1.0.0" name="twist">
<data name="header">
<data name="seq">0</data>
<data name="stamp">
<data name="sec">1</data>
<data name="nsec">0</data>
</data>
<data name="frame_id">base_link</data>
</data>
<data name="twist">
<data name="linear">
<data name="x">1.0</data>
<data name="y">0</data>
<data name="z">1.0</data>
</data>
<data name="angular">
<data name="x">0.3</data>
<data name="y">0</data>
<data name="z">0</data>
</data>
</data>
</data>
In order to avoid this side-effect, instead of defining the <data> element directly at the global level, we first define a data type, then define a data element of that type inside message:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="https://stackoverflow.com/message/1.0.0"
elementFormDefault="qualified"
xmlns="https://stackoverflow.com/message/1.0.0"
>
<xs:complexType name="data" mixed="true">
<xs:sequence>
<xs:element name="data" type="data" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:element name="message">
<xs:complexType>
<xs:sequence>
<xs:element name="from" type="xs:string"/>
<xs:element name="to" type="xs:string"/>
<xs:element name="type" type="xs:string"/>
<xs:element name="data" type="data" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Notice that we end up having to define the <data> element twice β€” once inside the data type, and again inside <element> β€” but apart a little work duplication this is of no consequence.

Related

Handle two XML files with one schema file

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?

cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found

I am trying to understand <any> element in xsd. I had two xsds.
Book Catalogue.xsd
<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.w3schools.com" xmlns="http://www.w3schools.com"
elementFormDefault="qualified">
<xs:element name="BookCatalogue">
<xs:complexType>
<xs:sequence>
<xs:element name="Book" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Title" type="xs:string" />
<xs:element name="Author" type="xs:string" />
<xs:element name="Date" type="xs:string" />
<xs:element name="ISBN" type="xs:string" />
<xs:element name="Publisher" type="xs:string" />
<xs:any namespace="##any" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Reviewer.xsd
<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.w3schools.com" xmlns="http://www.w3schools.com"
elementFormDefault="qualified">
<xs:element name="Reviewer">
<xs:complexType>
<xs:sequence>
<xs:element name="Name">
<xs:complexType>
<xs:sequence>
<xs:element name="First" type="xs:string" />
<xs:element name="Last" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
But if i validate the below xml based on above xsd, i am getting cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'p:Reviewer'. error. Does both xsd file should not be in same namespace?
<?xml version="1.0" encoding="UTF-8"?>
<pr:BookCatalogue xmlns:pr="http://www.w3schools.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3schools.com AddRequest.xsd ">
<pr:Book>
<pr:Title>pr:Title</pr:Title>
<pr:Author>pr:Author</pr:Author>
<pr:Date>pr:Date</pr:Date>
<pr:ISBN>pr:ISBN</pr:ISBN>
<pr:Publisher>pr:Publisher</pr:Publisher>
<p:Reviewer xmlns:p="http://www.w3schools.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3schools.com Children.xsd ">
<p:Name>
<p:First>p:First</p:First>
<p:Last>p:Last</p:Last>
</p:Name>
</p:Reviewer>
</pr:Book>
</pr:BookCatalogue>
Two options...
Option One: If you do not want to have to have the definition of p:Reviewer present, add processContents="lax" to your xs:any element:
<xs:any namespace="##any" minOccurs="0" processContents="lax"/>
Per XML Schema Part 0: Primer Second Edition:
The lax value of the processContents attribute instructs an XML
processor to validate the element content on a can-do basis: It will
validate elements and attributes for which it can obtain schema
information, but it will not signal errors for those it cannot obtain
any schema information.
See also XML Validation in Java: processContents=β€œlax” seems not to work correctly.
You should also carefully adjust your xsi:schemaLocation values to point to the actual filename of each XSD for each namespace in play. Here is your XML instance with the changes that I made:
<?xml version="1.0" encoding="UTF-8"?>
<pr:BookCatalogue
xmlns:pr="http://www.w3schools.com"
xmlns:p="http://www.w3schools.com/1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3schools.com BookCatalogue.xsd http://www.w3schools.com/1 Reviewer.xsd">
<pr:Book>
<pr:Title>pr:Title</pr:Title>
<pr:Author>pr:Author</pr:Author>
<pr:Date>pr:Date</pr:Date>
<pr:ISBN>pr:ISBN</pr:ISBN>
<pr:Publisher>pr:Publisher</pr:Publisher>
<p:Reviewer>
<p:Name>
<p:First>p:First</p:First>
<p:Last>p:Last</p:Last>
</p:Name>
</p:Reviewer>
</pr:Book>
</pr:BookCatalogue>
Note: Make sure that the targetNamespace in Review.xsd matches what's declared for it in BookCatalogue.xml's xsi:schemaLocation attribute.
Option Two: If you do want to insist that the definition of p:Reviewer be present, just make the above changes to be sure that Review.xsd can be found per the xsi:schemaLocation mechanism. No processContents setting is required; it defaults to strict.

Unique element in XSD sequence

I'd like to have an XSD to valide an XML containing file elements with many aliases but each alias with a different value.
This is my XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<folder>
<files>
<fileList>
<file>
<title>Document1</title>
<fileAlias>
<alias>Alias1</alias>
<alias>Alias2</alias>
</fileAlias>
</file>
</fileList>
</files>
</folder>
The former XML is good because Alias1 != Alias2
How could I specify it in my XSD:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="folder" type="folderType" />
<xs:complexType name="folderType">
<xs:sequence>
<xs:element name="files" type="filesType" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="filesType">
<xs:sequence>
<xs:element name="fileList" type="fileListType" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="fileListType">
<xs:sequence>
<xs:element maxOccurs="unbounded" name="file" type="fileType" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="fileType">
<xs:sequence>
<xs:element name="title" type="xs:string" />
<xs:element name="fileAlias" type="fileAliasType" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="id" type="xs:string" />
<xs:attribute name="type" type="xs:int" />
</xs:complexType>
<xs:complexType name="fileAliasType">
<xs:sequence>
<xs:element maxOccurs="unbounded" name="alias" type="xs:string" minOccurs="1" />
</xs:sequence>
</xs:complexType>
</xs:schema>
I've tried with xsd:unique but I think is for attributes not for XML element text values.
If I understand well your need then xs:unique should be the right way. Following modification of fileType complex type should be enough.
<xs:complexType name="fileType">
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="fileAlias" type="fileAliasType" minOccurs="0" maxOccurs="unbounded">
<xs:unique name="alias_unique">
<xs:selector xpath="alias"/>
<xs:field xpath="."/>
</xs:unique>
</xs:element>
</xs:sequence>
<xs:attribute name="id" type="xs:string"/>
<xs:attribute name="type" type="xs:int"/>
</xs:complexType>
This will validate
<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML file generated by XMLSpy v2013 sp1 (http://www.altova.com)-->
<folder xsi:noNamespaceSchemaLocation="unique.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<files>
<fileList>
<file id="String" type="0">
<title>String</title>
<fileAlias>
<alias>String1</alias>
<alias>String2</alias>
<alias>String3</alias>
</fileAlias>
</file>
</fileList>
</files>
</folder>
This won't
<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML file generated by XMLSpy v2013 sp1 (http://www.altova.com)-->
<folder xsi:noNamespaceSchemaLocation="unique.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<files>
<fileList>
<file id="String" type="0">
<title>String</title>
<fileAlias>
<alias>String1</alias>
<alias>String1</alias>
<alias>String3</alias>
</fileAlias>
</file>
</fileList>
</files>
</folder>

How can i validate multiple XML records in a single file using XSD schema in C#?

I am new to XML. I have a file with multiple XML records in it as shown below:
<event> //Record 1
<sequence>1</sequence>
<date>5-Feb-2012</date>
<time>00:00:42</time>
<severity>0</severity>
<errorcode>0</errorcode>
</event>
<event> //Record 2
<sequence>2</sequence>
<date>5-Feb-2012</date>
<time>00:00:51</time>
<severity>0</severity>
<errorcode>0</errorcode>
</event>
I need to validate this input file. I have written a schema as given below:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="event">
<xs:complexType>
<xs:sequence>
<xs:element name="sequence" type="xs:integer"/>
<xs:element name="date" type="xs:date"/>
<xs:element name="time" type="xs:time"/>
<xs:element name="severity" type="xs:integer"/>
<xs:element name="errorcode" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
This works if i have only one record in the file and throws exception saying "there are multiple root elements".
It's like the exception said: an XML document can only have a single root element. You need something like this:
<root>
<event></event>
<event></event>
</root>

How to I tell my JAXB output to include a reference to the XSD that created it?

Here is my pages.xsd
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mac="http://www.tvworks.com/tva/xml/ns/max/data-types"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:import namespace="http://www.tvworks.com/tva/xml/ns/max/data-types"
schemaLocation="http://developer.tva.tvworks.com/xml/ns/max/data-types-3.2.xsd"/>
<xs:element name="data">
<xs:complexType>
<xs:sequence>
<xs:element name="scenes" type="scenesType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="scenesType">
<xs:sequence>
<xs:element name="row" minOccurs="1" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="page" type="mac:page-ref"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
Here is my pages.xjb
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
version="2.1">
<bindings schemaLocation="pages.xsd" version="1.0"">
<schemaBindings>
<package name="com.mycompany.pages"/>
</schemaBindings>
</bindings>
</bindings>
Here is what I want the output to look like, notice the xsi:noNamespaceSchemaLocation="pages.xsd".
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="pages.xsd">
<scenes>
<row>
<page>page1</page>
</row>
<row>
<page>page2</page>
</row>
<row>
<page>page3</page>
</row>
<row>
<page>page4</page>
</row>
</scenes>
</data>
How do I get that attribute onto the data element the JAXB output automatically?
Set property jaxb.noNamespaceSchemaLocation with the desired value on your Marshaller.
EDIT: check the section on supported properties in the Marshaller documentation as well as method setProperty for additional info.

Resources