XSD key not in root element and complex keys - validation

I searched for this, but can't find solution to my problem, so please don't trash this question.
We have a service with very complex XML configuration which is described by XSD. There are many rules that must be obeyed for things to run smoothly. XSD describes structure of configuration, but not the rules, which we must do now. After creating some global rules we have to do some more complex now and we encountered a problem. It seams like validator only uses key/keyref/unique from root element. I've created small XSD and XML file to illustrate that:
XSD:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://test.org/XMLSchema.xsd"
elementFormDefault="qualified"
xmlns="http://test.org/XMLSchema.xsd"
xmlns:t="http://test.org/XMLSchema.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Orders" type="t:OrdersList">
<xs:key name="OrderNo">
<xs:selector xpath="./t:Order" />
<xs:field xpath="#Number" />
</xs:key>
</xs:element>
<xs:complexType name="OrdersList">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Order" nillable="false" type="t:Order" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Order">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="Lines" nillable="false" type="t:OrdersLinesList" />
</xs:sequence>
<xs:attribute name="Number" use="optional" type="xs:string" />
<xs:attribute name="ClientId" use="optional" type="xs:int" />
</xs:complexType>
<xs:complexType name="OrdersLinesList">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Line" nillable="false" type="t:OrderLine">
<!-- THE PROBLEM -->
<xs:key name="LineNoKey">
<xs:selector xpath="./t:Line" />
<xs:field xpath="#LineNumber" />
</xs:key>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="OrderLine">
<xs:attribute name="LineNumber" use="optional" type="xs:string" />
<xs:attribute name="ProductId" use="optional" type="xs:int" />
<xs:attribute name="Amount" use="optional" type="xs:decimal" />
</xs:complexType>
</xs:schema>
XML:
<?xml version="1.0" encoding="utf-8"?>
<Orders xmlns="http://test.org/XMLSchema.xsd">
<Order Number="0001/5/13" ClientId="123">
<Lines>
<Line LineNumber="1" ProductId="123" Amount="4" />
<Line LineNumber="2" ProductId="124" Amount="4" />
</Lines>
</Order>
<Order Number="0002/5/13" ClientId="123">
<Lines>
<Line LineNumber="1" ProductId="123" Amount="4" />
<!-- Duplicate number - it DOES validate as expected. -->
<Line LineNumber="1" ProductId="124" Amount="4" />
</Lines>
</Order>
<!-- Duplicate number - it doesn't validate as expected. -->
<Order Number="0002/5/13" ClientId="123">
<Lines>
<Line LineNumber="1" ProductId="123" Amount="4" />
<Line LineNumber="2" ProductId="124" Amount="4" />
</Lines>
</Order>
</Orders>
I have a few questions which I can't find any sensible answer:
How to solve the above. LineNumber must be unique, but only within Order/Lines.
Is it possible to allow keyref to contain non existing virtual value (our service uses some predefined... let say things. Custom ones are defined in XML to allow extending functionality, but in most of the cases, users will use predefined ones)
Is there any way to determine if list of elements within a tag (something like Lines above) has at least one tag with attribute set to certain value. Good example would be to describe it like a list of tables with unique names, that has list of columns with unique names and at least one of the columns is a primary key.

This is the corrected constraint for Lines/Line:
<xs:complexType name="Order">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="Lines" nillable="false" type="t:OrdersLinesList">
<!-- THE PROBLEM SOLVED -->
<xs:key name="LineNoKey">
<xs:selector xpath="t:Line"/>
<xs:field xpath="#LineNumber"/>
</xs:key>
</xs:element>
</xs:sequence>
<xs:attribute name="Number" use="optional" type="xs:string"/>
<xs:attribute name="ClientId" use="optional" type="xs:int"/>
</xs:complexType>
If always helps if you can visualize your constraints, to understand the scope they act upon:
The correct diagram:
vs. the original one:
You can see that the selector rooted in the element Line is looking for yet another Line (./t:Line); and even if you fix the selector, it'll always match at most one attribute. The idea of a key is that the selector should match a set of nodes among which the field must be present and unique.
The above should take care of 1.
No.
Not based on an attribute. To stick with your parallel, for XSD 1.0 I would probably enforce an element called PrimaryKey, which should contain one or more references to names of the other columns; as if instead of using the PRIMARY KEY constraint clause in a column definition, I would enforce the use of the same at the table level.

Related

Where is the schema of `child-resources` specified?

I'm trying to find where the schema of the result of a child-resources query is specified in the xsd. It's clearly not a primitiveContent (specified in responsePrimitive) because that doesn't contain the named child-resources arrays.
I think this is in the CDT-responsePrimitive-v.xsd file. In Resourcewrapper you have "m2m:sg_regularResource":
<xs:complexType name="resourceWrapper">
<xs:sequence>
<xs:choice minOccurs="1" maxOccurs="1">
...
<xs:element ref="m2m:sg_regularResource" />
...
</xs:choice>
<xs:element name="URI" type="xs:anyURI" />
</xs:sequence>
</xs:complexType>
In any of the resources that is a "m2m:sg_regularResource" you can find a section like this that allows for "included" child resources:
...
<!-- Child Resources -->
<xs:choice minOccurs="0" maxOccurs="1">
<xs:element name="childResource" type="m2m:childResourceRef" minOccurs="1" maxOccurs="unbounded" />
<xs:choice minOccurs="1" maxOccurs="unbounded">
<xs:element ref="m2m:aResourceType" />
<xs:element ref="m2m:anotherResourceType" />
</xs:choice>
</xs:choice>
...

XSD for auto closing tag in complexType

I have this in my XML file:
<rooms>
<room id="1" beds="1" windows="0"/>
<room id="2" beds="2" windows="0"/>
</rooms>
And this in my XSD file:
<xs:complexType name="Rooms">
<xs:sequence>
<xs:element name="room" type="Room"/>
</xs:sequence>
<xs:attribute name="count" type="xs:integer"/>
</xs:complexType>
<xs:complexType name="Room">
<xs:attribute name="id" type="xs:integer"/>
<xs:attribute name="beds" type="xs:integer"/>
<xs:attribute name="windows" type="xs:integer"/>
</xs:complexType>
But I got this error : Element 'room': This element is not expected.
When I put <room id="1" beds="1" windows="0"></room> I don't have the error anymore and if I have only one room I don't have the error, so it's basically because of the auto closing tag.
How can I fix this?
Try specifying values for minOccurs and maxOccurs to your room element inside the sequence. I think the default expected number of occurrences is 1. Something like:
<xs:sequence>
<xs:element name="room" type="Room" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>

How to use XPath to find nodes in the XML attribute with ref?

I am trying to access the attribute/element nodes with ref in the below xsd
<xs:attributeGroup name="arcAttrs">
<xs:attribute ref="xlink:type" use="required" fixed="arc"/>
<xs:attribute ref="xlink:arcrole"/>
<xs:attribute ref="xlink:title"/>
<xs:attribute ref="xlink:show"/>
<xs:attribute ref="xlink:actuate"/>
<xs:attribute ref="xlink:from"/>
<xs:attribute ref="xlink:to">
<xs:annotation>
<xs:documentation>
from and to have default behavior when values are missing
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:group name="arcModel">
<xs:sequence>
<xs:element ref="xlink:title" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:group>
<xs:complexType name="arcType">
<xs:group ref="xlink:arcModel"/>
<xs:attributeGroup ref="xlink:arcAttrs"/>
</xs:complexType>
I try to access it by
<bindings node="xs:complexType[#name='arcType']">
<bindings node="xs:group/xs:element[#ref='xlink:title']">
<property name="arcModelTitle"/>
</bindings>
</bindings>
but it doesn't work…… what should I do about this?
What I want to do is : generate JAVA package from xsd by xjc. However,there’re some name conflict in the xsd, like the error below:
[ERROR] Property "Title" is already defined. Use <jaxb:property> to resolve this conflict.
line 197 of file:/D:/0Ubiloc/TEST/xlink.xsd
[ERROR] The following location is relevant to the above error
line 183 of file:/D:/0Ubiloc/TEST/xlink.xsd
so I want to redefined the name of the attribute or the element. But it failed to get the node(attribute/element) with ref, just like the code I stick out on the floor 1
Thanks in advance

case-insensitive key in xsd

I have an XSD embedded into an XML like this:
<Replacements>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Replacements">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="Replace" />
</xs:sequence>
</xs:complexType>
<xs:key name="ReplaceKey">
<xs:selector xpath="./Replace"/>
<xs:field xpath="#old"/>
</xs:key>
</xs:element>
<xs:element name="Replace">
<xs:complexType>
<xs:attribute name="old" type="AnythingButLowerCase" use="required" />
<xs:attribute name="new" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:simpleType name="AnythingButLowerCase">
<xs:restriction base="xs:string">
<xs:pattern value="[^a-z]+"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
<Replace old="A1020____9" new="A1020"/>
<Replace old="a1020____9" new="A1020"/>
</Replacements>
I've used xs:key to define a unique-key on "old" attribute of Replace elements.
my problem is I want this key to be CASE-INSENSITIVE.
I've read so many documents indicating I can use xsd functions like upper-case or translate to solve this, but if I write something like
<xs:field xpath="upper-case(#old)"/>
VS2010 gives me a warning like this:
'upper-case(#old)' is an invalid XPath for selector or field.
What is it I'm doing wrong?
Thanks :)
The correct XPath function is "upper-case", not "upper case". Just add in the hyphen.
OK!
I got that!
Using functions in an xpath for a xs:field is not allowed.
The workaround for what I was seeking is to define a simpleType and put a restriction there not allowing lower-case letters.
Something like this:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<Replacements>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Replacements">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="Replace" />
</xs:sequence>
</xs:complexType>
<xs:key name="ReplaceKey">
<xs:selector xpath="./Replace"/>
<xs:field xpath="#old"/>
</xs:key>
</xs:element>
<xs:element name="Replace">
<xs:complexType>
<xs:attribute name="old" type="AnythingButLowerCase" use="required" />
<xs:attribute name="new" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:simpleType name="AnythingButLowerCase">
<xs:restriction base="xs:string">
<xs:pattern value="[^a-z]+"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
<Replace old="A1020____9" new="A1020"/>
<Replace old="a1020____9" new="A1020"/>
</Replacements>
Now this serves as what I want it to.

Why won't this Schema validate this XML file?

The XML file:
<Lista count="3">
<Pelicula nombre="Jurasic Park 3">
<Genero>Drama</Genero>
<Director sexo="M">Esteven Spielberg</Director>
<Temporada>
<Anho>2002</Anho>
<Semestre>Verano</Semestre>
</Temporada>
</Pelicula>
<Pelicula nombre="Maldiciones">
<Genero>Ficcion</Genero>
<Director sexo="M">Pedro Almodovar</Director>
<Temporada>
<Anho>2002</Anho>
<Semestre>Verano</Semestre>
</Temporada>
</Pelicula>
<Pelicula nombre="Amor en New York">
<Genero>Romance</Genero>
<Director sexo="F">Katia Hertz</Director>
<Temporada>
<Anho>2002</Anho>
<Semestre>Verano</Semestre>
</Temporada>
</Pelicula>
</Lista>
And here's the XML Schema file I made, it's not working. :\
<xsd:complexType name="Lista">
<xsd:attribute name="count" type="xsd:integer" />
<xsd:complexContent>
<xsd:element name="Pelicula" type="xsd:string">
<xsd:attribute name="nombre" type="xsd:string" />
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Genero" type="generoType"/>
<xsd:element name="Director" type="directorType">
<xsd:attribute name="sexo" type="sexoType"/>
</xsd:element>
</xsd:element name="Temporada">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Anho" type="anhoType" />
<xsd:element name="Semestre" type="semestreType" />
</xsd:sequence>
</xsd:complexType>
<xsd:element></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:complexContent>
</xsd:complexType>
<xsd:simpleType name="sexoType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="F"/>
<xsd:enumeration value="M"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="directorType">
<xsd:restriction base="xsd:string" />
</xsd:simpleType>
<xsd:simpleType name="generoType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Drama"/>
<xsd:enumeration value="Accion"/>
<xsd:enumeration value="Romance"/>
<xsd:enumeration value="Ficcion"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="semestreType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Verano"/>
<xsd:enumeration value="Invierno"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="anhoType">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="1970"/>
<xsd:maxInclusive value="2020"/>
</xsd:restriction>
</xsd:simpleType>
Try declaring and using your types separately. This makes the XSD a bit longer, but less nested and more readable (and more reusable, too):
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- document element -->
<xs:element name="Lista" type="listaType" />
<!-- type definitions -->
<xs:complexType name="listaType">
<xs:sequence>
<xs:element name="Pelicula" type="peliculaType" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="count" type="countType" />
</xs:complexType>
<xs:complexType name="peliculaType">
<xs:all>
<xs:element name="Genero" type="generoType" />
<xs:element name="Director" type="directorType" />
<xs:element name="Temporada" type="temporadaType" />
</xs:all>
<xs:attribute name="nombre" type="xs:string" />
</xs:complexType>
<xs:complexType name="directorType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="sexo" type="sexoType" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="temporadaType">
<xs:all>
<xs:element name="Anho" type="anhoType" />
<xs:element name="Semestre" type="semestreType" />
</xs:all>
</xs:complexType>
<xs:simpleType name="sexoType">
<xs:restriction base="xs:string">
<xs:enumeration value="F" />
<xs:enumeration value="M" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="generoType">
<xs:restriction base="xs:string">
<xs:enumeration value="Drama" />
<xs:enumeration value="Accion" />
<xs:enumeration value="Romance" />
<xs:enumeration value="Ficcion" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="semestreType">
<xs:restriction base="xs:string">
<xs:enumeration value="Verano" />
<xs:enumeration value="Invierno" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="anhoType">
<xs:restriction base="xs:integer">
<xs:minInclusive value="1970" />
<xs:maxInclusive value="2020" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="countType">
<xs:restriction base="xs:integer">
<xs:minInclusive value="0" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
The above validates your input XML.
Note that:
The convention for the XML Schema namespace prefix is xs (AFAIK - you can still go on and use xsd if you prefer).
The count attribute is really unnecessary, since the count can a) easily be calculated and b) there is a risk of something going wrong when the count attribute value and the actual count differ for some reason. Things that are derivable from the data should never be part of the data.
Oh, and to answer your initial question (why does mine not work):
You never declare an actual document element ("Lista"), you just declare its type. Compare with my solution.
In the complexType name="Lista":
attribute cannot be the first child of a complex type. Attributes must be declared after everything else.
complexContent cannot contain element.
in fact, you don't need a complexContent at all - just use a sequence instead.
In element name="Pelicula":
The type attribute is illegal when you declare a complexType within.
In the complexType for "Pelicula":
Again, attributes last.
Don't use a sequence unless you want to make any other order of children illegal. In this type of document I would guess child order is irrelevant.
In element name="Director":
You can't declare any attributes since when you already declared a type. Include the sexo attribute in the directorType
In simpleType name="directorType":
This should in reality be a complexType containing simpleContent with an extension. This way you can include the sexo attribute
Your XSD isn't even well formed XML.
Your XML iswas not well-formed, either. I have fixed it to be able to test in the first place.
P.S.: There is enough XSD documentation freely available to fix many of the basic problems you've had. There are XSD validators on the Net that help you by telling you what constructs are illegal. Knowing everything is absolutely not necessary, but a little reading + trial and error would have helped. ;-)
For a start:
<Semestre>Verano<Semestre>
...doesn't look well-formed.

Resources