XSD Applying global rules - xsd

Can we have some rule in XSD which says: All those elements having ID as its attribute should treat it as unique ID so that other elements should not use that ID.
How to apply that as getElementById("id") works only after that.
Thanks

If you have only digits for your identifier, you can't use xs:id.
Then here is a sample schema :
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="root" type="rootType">
<xs:key name="attritemIdentifier">
<xs:selector xpath="item"/>
<xs:field xpath="#XYZ"/>
</xs:key>
</xs:element>
<xs:complexType name="rootType">
<xs:sequence>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="XYZ" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
And here is a valid instance :
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item XYZ="12345">item0</item>
<item XYZ="XYZ1">item1</item>
<item XYZ="XYZ2">item2</item>
<item XYZ="XYZ3">item3</item>
<item XYZ="XYZ4">item4</item>
<item XYZ="XYZ5">item5</item>
<item XYZ="XYZ9">item6</item>
<item XYZ="XYZ7">item7</item>
</root>
As soon as you have to attribute XYZ with the same value, you'll get the following error :
cvc-identity-constraint.4.2.2: Duplicate key value [XYZ9] declared
for identity constraint "attritemIdentifier" of element "root"

Related

XSD - XNOR gate of 2 nodes

I trying to create a XSD which validates XML only if both nodes A and B exist or both does not exist (XNOR gate).
I have checked the internet, however, without any luck.
<root>
<A>a</A>
<B>b</B>
<C>c</C>
</root>
I have found a solution:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root" type="root"/>
<xs:complexType name="root">
<xs:sequence>
<xs:choice>
<xs:sequence>
<xs:element name="a" type="xs:string" />
<xs:element name="b" type="xs:string" />
</xs:sequence>
<xs:sequence></xs:sequence>
</xs:choice>
<xs:element name="c" type="xs:string" />
</xs:sequence>
</xs:complexType>

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.

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.

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.

XML schema for elements with same name but different sub-structure depending on context

I try to define a schema for XML documents I receive.
The documents look like:
<root>
<items>
<group name="G-1">
<item name="I-1"/>
<item name="I-2"/>
<item name="I-3"/>
<item name="I-4"/>
</group>
</items>
<data>
<group name="G-1" place="here">
<customer name="C-1">
<item name="I-1" count="3"/>
<item name="I-2" count="4"/>
</customer>
<customer name="C-2">
<item name="I-3" count="7"/>
</customer>
</group>
</data>
</root>
I tried XmlSpy and xsd.exe from .NET 2.0. Both created schema definitions which allow below <group> any number of <item> and <customer> elements. But what I'm looking for should restrict <group> below <items> to <item> elements, and <group> below <data> to <customer> elements.
Is this something xml schema is not capable at all?
The key points (see XML Schema Runtime Polymorphism via xsi:type and Abstract Types for complete and correct context/placement/usage) are:
Create a base type with (abstract="true" to prevent it from being used directly)
Note: the ref attribute replaces the name attribute for elements defined elsewhere
<xs:complexType name="CustomerType" abstract="true" >
<xs:sequence>
<xs:element ref="cust:FirstName" />
<xs:element ref="cust:LastName" />
<xs:element ref="cust:PhoneNumber" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="customerID" type="xs:integer" />
</xs:complexType>
Create two or more derived types by extending or restricting the base type
<xs:complexType name="MandatoryPhoneCustomerType" >
<xs:complexContent>
<xs:restriction base="cust:CustomerType">
<xs:sequence>
<xs:element ref="cust:FirstName" />
<xs:element ref="cust:LastName" />
<xs:element ref="cust:PhoneNumber" minOccurs="1" />
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
and
<xs:complexType name="AddressableCustomerType" >
<xs:complexContent>
<xs:extension base="cust:CustomerType">
<xs:sequence>
<xs:element ref="cust:Address" />
<xs:element ref="cust:City" />
<xs:element ref="cust:State" />
<xs:element ref="cust:Zip" />
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Reference the base type in an element
<xs:element name="Customer" type="cust:CustomerType" />
In your instance XML document, specify the specific derived type as an xsi:type attribute
<cust:Customer customerID="12345" xsi:type="cust:MandatoryPhoneCustomerType" >
<cust:FirstName>Dare</cust:FirstName>
<cust:LastName>Obasanjo</cust:LastName>
<cust:PhoneNumber>425-555-1234</cust:PhoneNumber>
</cust:Customer>
or:
<cust:Customer customerID="67890" xsi:type="cust:AddressableCustomerType" >
<cust:FirstName>John</cust:FirstName>
<cust:LastName>Smith</cust:LastName>
<cust:Address>2001</cust:Address>
<cust:City>Redmond</cust:City>
<cust:State>WA</cust:State>
<cust:Zip>98052</cust:Zip>
</cust:Customer>
Yes, XSD can handle this. I generated this schema from Visual Studio 2008 (much faster than doing it by hand) and it will do what you're looking for:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<xs:element name="group">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="item">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="data">
<xs:complexType>
<xs:sequence>
<xs:element name="group">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="customer">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="item">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="count" type="xs:unsignedByte" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="place" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Resources