Another XSD question - how can I achieve that the following XML elements are both valid:
<some-element>
<type>1</type>
<a>...</a>
</some-element>
<some-element>
<type>2</type>
<b>...</b>
</some-element>
The sub-elements (either <a> or <b>) should depend on the content of <type> (could also be an attribute). It would be so simple in RelaxNG - but RelaxNG doesn't support key integrity :(
Is there a way to implement this in XSD?
Note: XML schema version 1.1 supports <xs:alternative>, which might be a solution, but afaik no reference implementation (e.g. libxml2) supports this yet. So I'm searching for workarounds. The only way I've come up with is:
<type>1</type>
<some-element type="1">
<!-- simple <xs:choice> between <a> and <b> goes here -->
<a>...</a>
</some-element>
<!-- and now create a keyref between <type> and #type -->
The best solution is to remove the <type/> element and only have a xs:choice for <a/> and <b/> and let the application consuming the xml sort out the type.
Another solution might be to have a xs:choice for <a/> and <b/> use an xslt script to do a validation of the <type/> element in relation to <a/> and <b/>.
First validate the xml against the xmlschema then use the xslt to do a transformation on it, if the result of the transform is empty string it is valid otherwise show the resulting string as an error message.
Something like this...
XmlSchema:
<xs:element name="some-element">
<xs:complexType>
<xs:sequence>
<xs:element name="type" type="xs:integer" />
<xs:choice>
<xs:element name="a" type="xs:string" />
<xs:element name="b" type="xs:string" />
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Xslt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:demo="uri:demo:namespace">
<xsl:output method="text" />
<xsl:template match="/demo:some-element">
<xsl:if test="type = 1 and not(demo:a)">
When type equals 1 element a is requred.
</xsl:if>
<xsl:if test="type = 2 and not(demo:b)">
When type equals 2 element b is requred.
</xsl:if>
</xsl:template>
</xsl:stylesheet>
No, XML Schema 1.0 cannot do this.
Related
Is it possible in XSD to name an element dynamically?
I have a complexType with a varying (but limited) number of elements (x-n), each of which has a complicated substructure. I can copy and paste one (x-1) and just change the number for the name of each of the copies (x-2, x3, and so on), but it'd be cleaner if I didn't have to.
For example, as it is now:
<xs:schema attributeFormDefault="unq1" elementFormDefault="q1" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="r1">
<xs:complexType><xs:sequence>
<xs:element name="w-s">
<xs:complexType><xs:sequence maxOccurs="4">
<xs:element name="x-1" minOccurs="0">
<xs:complexType><xs:sequence>
<!-- long tedious substructure goes here -->
</xs:sequence></xs:complexType>
</xs:element>
<xs:element name="x-2" minOccurs="0">
<xs:complexType><xs:sequence>
<!-- long tedious substructure goes here -->
</xs:sequence></xs:complexType>
</xs:element>
<xs:element name="x-3" minOccurs="0">
<xs:complexType><xs:sequence>
<!-- long tedious substructure goes here -->
</xs:sequence></xs:complexType>
</xs:element>
<xs:element name="x-4" minOccurs="0">
<xs:complexType><xs:sequence>
<!-- long tedious substructure goes here -->
</xs:sequence></xs:complexType>
</xs:element>
</xs:sequence></xs:complexType>
</xs:element>
</xs:sequence></xs:complexType>
</xs:element>
</xs:schema>
Looking through w3schools now (https://www.w3schools.blog/xsd-xml-schema-definition-tutorial), the answer is not jumping out at me yet, and it's starting to look like the answer is "No.".
I can copy and paste one (x-1) and just change the number
If each element x-n has the same content then you should use the same tag name for all of these tags. That will require a change in the XML format, so I would also recommend that you stop using this style:
<element name='x-n' ...>
...and start using this instead:
<x index="n">
This will make your life much easier because XML schema expects the tag name to indicate the type of content.
I understand that you may not be able to change the XML format, but I think it's important to point out that your current style of XML is not best practice.
Judging by these stackoverflows, the answer appears to be "Not only no, but also you're wrong for asking" :-p
xml schema list of incremental element name
Can't design xsd schema - because of a variable element name
XML variable tag names
The better solution is to restructure the XSD so that the x-n element has a sub-element indicating the value of n, like so:
<xs:schema attributeFormDefault="unq1" elementFormDefault="q1" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="r1">
<xs:complexType><xs:sequence>
<xs:element name="w-s">
<xs:complexType><xs:sequence maxOccurs="4">
<xs:element name="x" minOccurs="0">
<xs:complexType><xs:sequence>
<xs:element name="x-number">
<!-- long tedious substructure goes here -->
</xs:sequence></xs:complexType>
</xs:element>
</xs:sequence></xs:complexType>
</xs:element>
</xs:sequence></xs:complexType>
</xs:element>
</xs:schema>
So I found this post which is very similar to what I want to achieve, but I can't quite figure out if it's not possible to do what I am attempting, or if I'm just missing something...
Use XML Schema to extend an element rather than a complexType
The gist is that I have an XSD that contains a defined Element. I would prefer not to edit this original xsd file. Is there any way for me to extend the Element so that I also can add my own attributes, "attributeC"?
The other post creates a new complexType of fooType, and places the element inside of it, and extends fooType to contain more elements. By doing so, they are able to achieve an Element that contains fooElement, and two other added elements. The issue is that I'd like to add to the Element itself, not add to the element at the same level.
XSD1
<xs:schema xmlns:bas="http://www.base.com"
xmlns="https://www.adding.com"
attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="https://www.adding.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import schemaLocation="XSD2.xsd" namespace="http://www.base.com" />
<xs:complexType name="FileSpecType">
<xs:sequence>
<xs:element ref="bas:FileSpec"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="FullFileSpecType">
<xs:complexContent mixed="false">
<xs:extension base="FileSpecType">
<xs:attribute name="attributeC" type="xs:string" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="FileSpec" type="FileSpecType" />
This code ends up generating a new FileSpec
<FileSpec AttributeC="attCval" />>
<bas:FileSpec/>
</FileSpec>
What I want to achieve is more like...
<bas:FileSpec AttributeA="attAval" AttributeB="attBval" AttributeC="attCval/>
Can anybody point me in the right direction to solve my issues?
I'm thinking I could define my own dataType=FileSpec and add my own reference to external attributes, but that'd require manually copying over each attribute that exists in my original XSD2 FileSpec so I'd prefer to avoid that if possible. Then I think I could take that new FileSpec that I created and redefine the older FileSpec with it. Is this possible to do? It sounds like a lot of work that must have a simpler solution.
Its somewhat unclear what you are trying to do, if this does not cover it, please post the schema you are including as well as the XML you are trying to produce including the containing element.
You can extend an existing xs:complexType like this.
<?xml version="1.0" encoding="utf-8" ?>
<!--Created with Liquid Studio 2020 (https://www.liquid-technologies.com)-->
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="BaseType">
<xs:attribute name="attributeA" type="xs:string" />
</xs:complexType>
<xs:complexType name="ExtendedType">
<xs:complexContent>
<xs:extension base="BaseType">
<xs:attribute name="attributeB" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="RootElm">
<xs:complexType>
<xs:sequence>
<xs:element name="BaseElm" type="BaseType" />
<xs:element name="ExtendedElm" type="ExtendedType" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
This allows you to produce XML that looks like this
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Studio 2020 (https://www.liquid-technologies.com) -->
<RootElm xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<BaseElm attributeA="XX" />
<ExtendedElm attributeA="YY" attributeB="ZZ" />
</RootElm>
There is another way to make use of the ExtendedType when ever its valid to use a BaseType
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Studio 2020 (https://www.liquid-technologies.com) -->
<RootElm xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<BaseElm xsi:type="ExtendedType" attributeB="XX" attributeA="YY" />
<ExtendedElm attributeA="XX" attributeB="YY" />
</RootElm>
Notice the xsi:type="ExtendedType" in the BaseElm, this tells the XML processor that this element actually contains data for the ExtendedType.
My document contains A elements with IDs and B Elements which reference the As, like this:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="file:\\\refissue.xsd">
<A id="x"/>
<A id="y"/>
<B><Aref idref="x" /></B>
</root>
When I validate against my simple schema (see below) I get the following error:
cvc-identity-constraint.4.3: Key 'ref' with value 'x' not found for identity constraint of element 'root'.
If I change the ordering of the A element to
<A id="y"/>
<A id="x"/>
the document validates without any errors.
Why does the validation result depend on the ordering of the elements?
Is this a bug in the validator or in my schema?
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="A">
<xs:complexType>
<xs:attribute name="id" type="xs:ID" />
</xs:complexType>
<xs:key name="A.KEY">
<xs:selector xpath="." />
<xs:field xpath="#id" />
</xs:key>
</xs:element>
<xs:element maxOccurs="unbounded" name="B">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Aref">
<xs:complexType>
<xs:attribute name="idref" type="xs:IDREF" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:keyref name="ref" refer="A.KEY">
<xs:selector xpath="B/Aref" />
<xs:field xpath="#idref" />
</xs:keyref>
</xs:element>
</xs:schema>
I tried the validation with Eclipse (which uses xerces, I think), xerces-c 3.1.1, xmlstarlet 1.5.0 and libxml2 2.7.8 and I get the error only with eclipse and xerces.
You're right, validity against an identity constraint should not depend on the order of elements in the input.
Here I think the problem is that the schema is not quite right, and Xerces is having trouble generating a useful diagnosis of the problem. (The fact that libxml doesn't report an error is just a consequence of its incomplete coverage of XSD.)
Your key constraint should be defined on the scope of the element within which the key values need to be unique -- so on the root element, not on the A element. (As defined, your A.KEY constraint requires that the string value of each A element be unique within that A element, which will always be the case. The fact that the id attribute is declared as being of type xs:ID does require uniqueness, of course. And similarly, the fact that the Aref idref attribute is declared as being of type xs:IDREF means that your key and keyref declarations are not actually doing much work here that's not already being done by ID and IDREF.)
Once you move the declaration of A.KEY to the declaration of the root element, Xerces and Saxon agree that the schema is OK and the document is valid.
I had a similar problem in Eclipse until the xs:key and the xs:keyref were both explicitly set to the same type. In my case I set to both to xs:string(I also was using xs:unique and a keyref reference to the unique but it seems to work the same way for key and keyref pairs).
So for example if the key is based on an element that looks like this:
<xs:complexType name="elementTypeWithKey'>
<xs:attribute name="theKey" type="xs:string"/>
</xs:complexType>
and the theKey attribute is explicitly xs:string, make sure that the attribute used as a keyRef is also explicitly xs:string:
<xs:complexType name="elementTypeWithKeyRef">
<xs:attribute name="theKeyRef" type="xs:string"/>
</xs:complexType>
I have following xsd :
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="employeeType"/>
<xs:complexType name="employeeType">
<xs:sequence>
<xs:element type="xs:string" name="name"/>
<xs:element type="xs:int" name="age"/>
<xs:element type="xs:string" name="address"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
If i set value only for Name i.e
EmployeeDocument request=EmployeeDocument.Factory.newInstance();
EmployeeType emp=EmployeeType.Factory.newInstance();
emp.setName("Name");
request.setEmployee(emp);
Then XMLBeans generating following xml:
<employee>
<name>Name</name>
</employee>
But i need a following kind of xml to be generated ,means closing tags </> for all elements whose values are not set in program :
<employee>
<name>Name</name>
<age/>
<address/>
</employee>
well , XMLBeans generating <address/> if i set an empty string i.e emp.setAddress("");
Is there any way we could meet such requirement using XMLBeans , without setting empty string.
And more over we could not set empty string for element age which is of type int .
Any help would be appreciated.
The XMLSchema way to do this is add nillable="true" to your age and address elements. When you recompile the xsd with XMLBeans, you will have .setNilAge() and .setNilAddress() methods. The generated xml will look like:
<employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>Name</name>
<age xsi:nil="true"/>
<address xsi:nil="true"/>
</employee>
By the way, it is better to build up your document using .addNewEmployee() instead of .setEmployee() if possible. This avoids copying the employee instance into the document which is more expensive.
I have this xsd:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns="http://myschema.com/schema"
targetNamespace="http://myschema.com/schema"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="aType" mixed="true">
<xs:group ref="aElements" minOccurs="0" maxOccurs="unbounded"/>
</xs:complexType>
<xs:group name="aElements">
<xs:choice>
<xs:element name="a" type="aType"/>
</xs:choice>
</xs:group>
<xs:element name="b">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:group ref="aElements"/>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
and I try to validate this xml document against it:
<?xml version="1.0" encoding="utf-8" ?>
<b xmlns="http://myschema.com/schema">
<a/>
</b>
However, Visual Studio 2008's xml validator complains about the <a> element:
The element 'b' in namespace 'http://myschema.com/schema' has invalid child element 'a' in namespace 'http://myschema.com/schema'. List of possible elements expected: 'a'.
What is the problem?
Edit: Oops, when dumbing down the example I caused forgot to make the element optional inside the element, causing infinite recursion. The problem is still there with this mod, though.
ANSWER: The answer was that the xs:schema tag should include the elementFormDefault="qualified" attribute.
you define aElements with aType, and aType with aElements. i'm not an xsd expert, but how is that supposed to work?
You could make your life much easier using an editor for XSD development. We've been using Liquid XML Studio for ages, it makes life much easer.