xml: using conditioned attributes - xsd

I'm looking for a way to realize a scheme, where an element does have an attribute "topic" only when its enumeration has a specific value like in the upcoming example:
<article>
<type>Blogpost</type>
</article>
<article>
<type topic='news'>Article</type>
</article>
<article>
<type>Comment</type>
</article>
The challenge is to make it that the attribute will only be used when the value "Article" or "Documentary" is chosen. Furthermore I want only enumerations from predefined list to be valid. In case the right enumeration is chosen I want the attribute to be required in all other cases I don't want to have the attribute at all.
So far I tried the following schemes in order to do so but it doesn't work at all:
<xs:element name="type" minOccurs="0">
<xs:alternative test="#name='type'" type="type1"/>
<xs:alternative test="#name='type'" type="type2"/>
<xs:alternative type="xs:error"/>
</xs:element>
(...)
<xs:simpleType name="type1">
<xs:restriction base="xs:string">
<xs:enumeration value="Blogpost"/>
<xs:enumeration value="Comment"/>
<xs:enumeration value="Sentence"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="type2">
<xs:simpleContent>
<xs:extension base="type1">
<xs:attribute name="topic" type="topics" use='required'>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="Article"/>
<xs:enumeration value="Documentary"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType-->
I always get an error that any chosen element is 'not a valid value of "error"'. The other example I tried worked to make use the attribute however it allowed any text and didn't care about the enumeration restrictions making it basicly useless:
<xs:element name="type" minOccurs="0">
<xs:alternative test="#ItemType='type'" type="type1"/>
<xs:alternative test="#ItemType='type'" type="type2"/>
</xs:element>
(...)
How do I do it that the same element does only have the attribute when it is actually the right enumeration and still the restrictions to enumerations are valid? Is my approach to work with xs:alternative the right one in order to have a same element one time with and one time without an attribute?
I was not able to figure out right test conditions in order to work with xs:assert.

I now have a useful answer - sorry for the non-useful comments!
This question is almost identical yours: XSD 1.1 alternative test the contents of text()
. On that basis, I suggest that you try something like this (not tested, because I don't have a XSD1.1 processor)
<xs:element name="type" type="type2" minOccurs="0"/>
<xs:complexType name="type2">
<xs:simpleContent>
<xs:extension base="type1">
<xs:attribute name="topic" type="topics" use='required'/>
<xs:assert test="not ( #topic or ( #topic and ($value eq 'Article' or $value eq 'Documentary'))"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="type1">
<xs:restriction base="xs:string">
<xs:enumeration value="Article"/>
<xs:enumeration value="Documentary"/>
<xs:enumeration value="Blogpost"/>
<xs:enumeration value="Comment"/>
<xs:enumeration value="Sentence"/>
</xs:restriction>
</xs:simpleType>```

Thank you again for your approach #kimbert.
With your help I was able to figure out the assertion that is fullfilling the demand. I just had to adjust your idea slightly:
<xs:element name="type" type="type2" minOccurs="0"/>
<xs:complexType name="type2">
<xs:simpleContent>
<xs:extension base="type1">
<xs:attribute name="topic" type="topics"/>
<xs:assert test="#topic and ($value eq 'Article' or $value eq 'Documentary') or not ($value eq 'Article' or $value eq 'Documentary')"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="type1">
<xs:restriction base="xs:string">
<xs:enumeration value="Article"/>
<xs:enumeration value="Documentary"/>
<xs:enumeration value="Blogpost"/>
<xs:enumeration value="Comment"/>
<xs:enumeration value="Sentence"/>
</xs:restriction>
</xs:simpleType>
Like this the compiler now always demands the attribute "topic" in case the value "Article" or "Documentary" is asked for. In all other cases the attribute is ignored as it should be.

Related

XSD complexType with element AND simpleContent

Working with XML 1.1 in Oxygen XML Editor version 23.1.
Originally I wandted to make an xsd schema that can have a complexType-element with a child-element, an extension and a bunch of attributes. A first possible solution I was able to get here but figured out it didn't fit to my problem, because the child-element itself consists of several elements and attributes which makes the original approach invalid, causing the error message: "The content type of a derived type and that of its base must both be mixed or both be element-only. Type 'complexTypeContent' is mixed, but its base type is not".
To my problem itself: The aim is for the child-element random to only be used when the attribute until has the value 'random'. So in the end a XML-file like this should be valid:
<instruction>
<type repeat='1' until='random'><random start='1' end='6'/>Dice Roll</type>
</instruction>
Instead - if the attribute until has not the value "random" - the element random must not be allowed. So something like this should be forbidden:
<instruction>
<type repeat='1' until='2'><random start='1' end='6'/>Dice Roll</type>
</instruction>
With help from here I was able to modify my xsd-scheme to something like this. But as already stated, it doesn't compile without an error message:
<xs:element name="root">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="instruction" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="type">
<xs:alternative test="#until = 'random'" type="complexTypeContent"/>
<xs:alternative type="simpleTypeContent"/>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="complexTypeContent" mixed="true">
<xs:complexContent>
<xs:extension base="simpleTypeContent">
<xs:sequence>
<xs:element name="random" type="random" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="random">
<xs:attribute name="start">
<xs:simpleType>
<xs:restriction base="xs:integer"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="end">
<xs:simpleType>
<xs:restriction base="xs:integer"/>
</xs:simpleType>
</xs:attribute>
<xs:assert test="#start le #end"/>
</xs:complexType>
<xs:complexType name="simpleTypeContent" mixed="true">
<xs:simpleContent>
<xs:extension base="type2">
<xs:attribute name="until">
<xs:simpleType>
<xs:union memberTypes="type2 annotation xs:integer until"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="condition">
<xs:simpleType>
<xs:union memberTypes="type2 annotation extended"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="repeat" type='xs:integer'/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="type2">
<xs:restriction base="xs:string">
<xs:enumeration value="Dice Roll"/>
<xs:enumeration value="Wait"/>
<xs:enumeration value="Repeat"/>
<xs:enumeration value="Double Roll"/>
<xs:enumeration value="Instruction"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="until">
<xs:restriction base="xs:string">
<xs:enumeration value="end"/>
<xs:enumeration value="random"/>
<xs:enumeration value="Instruction"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="annotation">
<xs:restriction base="xs:string">
<xs:enumeration value="rolltwice"/>
<xs:enumeration value="halfcount"/>
<xs:enumeration value="doublecount"/>
<xs:enumeration value="roll-"/>
<xs:enumeration value="roll+"/>
<xs:enumeration value="numberChange"/>
<xs:enumeration value="NoNumberChange"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="extended">
<xs:restriction base="xs:string">
<xs:enumeration value="noRolling"/>
<xs:enumeration value="noEven"/>
<xs:enumeration value="noUneven"/>
<xs:enumeration value="stopped"/>
</xs:restriction>
</xs:simpleType>
The error messages I had now all imply that this solution is invalid because of the not mixed content of simpleTypeContent or because it has simpleContent which cannot be derived from the complex content of complexTypeContent. So, how do I get it working? I cannot figure out any working solution for the problem I am facing.
As far as I understand, XSD (not even 1.1) doesn't offer a way to restrict the mixed content text to some simple type, so the only way, if you really need that single element together with a certain list of values seems to be an assertion; that means, unfortunately, you need to duplicate the values you also want for an attribute.
So some (slightly adapted, see my comment about the `#until = 'random' check) sample schema would be
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1">
<xs:element name="root">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="instruction" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="type">
<xs:alternative test="#until = 'random'" type="complexTypeContent"/>
<xs:alternative type="simpleTypeContent"/>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="complexTypeContent" mixed="true">
<xs:complexContent>
<xs:extension base="simpleTypeContent">
<xs:sequence>
<xs:element name="random" type="random" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="random">
<xs:attribute name="start">
<xs:simpleType>
<xs:restriction base="xs:integer"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="end">
<xs:simpleType>
<xs:restriction base="xs:integer"/>
</xs:simpleType>
</xs:attribute>
<xs:assert test="#start le #end"/>
</xs:complexType>
<xs:complexType name="simpleTypeContent" mixed="true">
<xs:attribute name="until">
<xs:simpleType>
<xs:union memberTypes="type2 annotation xs:integer until"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="condition">
<xs:simpleType>
<xs:union memberTypes="type2 annotation extended"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="repeat" type='xs:integer'/>
<xs:assert test=". = ('Dice Roll', 'Wait', 'Repeat', 'Double Roll', 'Instruction')"/>
</xs:complexType>
<xs:simpleType name="type2">
<xs:restriction base="xs:string">
<xs:enumeration value="Dice Roll"/>
<xs:enumeration value="Wait"/>
<xs:enumeration value="Repeat"/>
<xs:enumeration value="Double Roll"/>
<xs:enumeration value="Instruction"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="until">
<xs:restriction base="xs:string">
<xs:enumeration value="end"/>
<xs:enumeration value="random"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="annotation">
<xs:restriction base="xs:string">
<xs:enumeration value="rolltwice"/>
<xs:enumeration value="halfcount"/>
<xs:enumeration value="doublecount"/>
<xs:enumeration value="roll-"/>
<xs:enumeration value="roll+"/>
<xs:enumeration value="numberChange"/>
<xs:enumeration value="NoNumberChange"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="extended">
<xs:restriction base="xs:string">
<xs:enumeration value="noRolling"/>
<xs:enumeration value="noEven"/>
<xs:enumeration value="noUneven"/>
<xs:enumeration value="stopped"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
and that then makes the first instruction in below sample (also slightly adapted as there was a spelling difference between the schema and the sample (Dice roll vs. Dice Roll) in your snippets) valid while the second is invalid:
<root>
<instruction>
<type repeat='1' until='random'><random start='1' end='6'/>Dice Roll</type>
</instruction>
<instruction>
<type repeat='1' until='2'><random start='1' end='6'/>Dice Roll</type>
</instruction>
</root>

How to use condition in maxInclusive restriction in xsd

I am using schema version 1.0. I want to put condition on maxInclusive.
Like
if person selected minor(age<18) then in age textbox he should not be able to enter more than 18
if he selected adult then we can have age limit till 123
Any help will be appreciated.
Try this.
<xs:element name="person">
<xs:element ref="age"/>
</xs:element>
<xs:element name="age">
<xs:alternative test="#PersonType='Age'" type="MinorAgeType"/>
<xs:alternative test="#PersonType='Age'" type="AdultAgeType"/>
<xs:alternative type="xs:error"/>
</xs:element>
<xs:simpleType name="MinorAgeType">
<xs:restriction base="xs:integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="17"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="AdultAgeType">
<xs:restriction base="xs:integer">
<xs:minInclusive value="18"/>
<xs:maxInclusive value="123"/>
</xs:restriction>
</xs:simpleType>

XML Schema validator error on attribute declaration

I get an error on validation:
Error - Line 14, 36: org.xml.sax.SAXParseException; lineNumber: 14; columnNumber: 36; s4s-elt-must-match.1: The content of 'simpleType' must match (annotation?, (restriction | list | union)). A problem was found starting at: attribute.
How to resolve it?
My XML fragment
<CHANEL_NAME lang="RUS/MD">N4</CHANEL_NAME>
And XSD:
<xs:element name="CHANEL_NAME">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:length value="40"/>
</xs:restriction>
<xs:attribute name="lang">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="MD"/>
<xs:enumeration value="RUS"/>
<xs:enumeration value="RUS/MD"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:simpleType>
</xs:element>
So I need in attribute 'lang' only determined values like 'MD', 'RUS' or 'RUS/MD'. I read examples and I guess it's OK.
Or is enumeration only for elements and not for attributes?
The problem is the first simpleType. Simple types can't have attribute.
You probably need a complex type with simple content. Something like:
<xs:element name="CHANEL_NAME">
<xs:complexType>
<xs:simpleContent>
<xs:restriction base="xs:string">
<xs:length value="40"/>
<xs:attribute name="lang">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="MD"/>
<xs:enumeration value="RUS"/>
<xs:enumeration value="RUS/MD"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
(Not tested.)
Also consider naming your anonymous types.
ps. Also consider using/restricting xs:language as language type.
Всего наилучшего.

How to declare a type in xml-schema?

I have a schema like below, the color elements of default and instance have identical restriction (red/green/blue). I want to move the restriction to higher level and set all color element with it (Like declare a type or enum in Java/C#)
How can I do for that?
<xs:element name="something">
<xs:complexType>
<xs:sequence>
<xs:element name="instance" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="color" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="red"/>
<xs:enumeration value="green"/>
<xs:enumeration value="blue"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="default">
<xs:complexType>
<xs:attribute name="color" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="red"/>
<xs:enumeration value="green"/>
<xs:enumeration value="blue"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
Define the type:
<xs:simpleType name="colorenum">
<xs:restriction base="xs:string">
<xs:enumeration value="red"/>
<xs:enumeration value="green"/>
<xs:enumeration value="blue"/>
</xs:restriction>
</xs:simpleType>
And reference it:
<xs:attribute name="color" type="colorenum" />

How make univoque my enumeration by xs:unique

Can anyone point me as to why the unique element in my XSD is not forcing unique-ness? This should throw an error because the last ScreenResult element does not contain a unique value for the Type attribute. I should also note that I'm truly after forcing one of each Type within ScreenResults (ScreenResult is required to exist 3 times, there are 3 types of screens and I am requiring unique-ness) so if there is a better way to accomplish that, I'm all for that as well.
Thank you.
Here is my XML snippet:
<ScreenResults>
<ScreenResult Type="Screen Type A">1</ScreenResult>
<ScreenResult Type="Screen Type B">1</ScreenResult>
<ScreenResult Type="Screen Type B">2</ScreenResult>
</ScreenResults>
Here is my XSD snippet (also note that my original XSD snippets span multiple files but I have verified all of my namespaces are correct):
<xs:element name="ScreenResults" type="import:ScreenResults" minOccurs="0" maxOccurs="1">
<xs:unique name="UniqueScreenResults">
<xs:selector xpath="ScreenResult" />
<xs:field xpath="#Type" />
</xs:unique>
</xs:element>
<!--============ ScreenResults =============-->
<xs:complexType name="ScreenResults">
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="ScreenResult" minOccurs="3" maxOccurs="3">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="enum:ScreenResult">
<xs:attribute name="Type" type="enum:ScreenType" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<!--============= ScreenType =============-->
<xs:simpleType name="ScreenType">
<xs:restriction base='xs:token'>
<xs:enumeration value='Screen Type A' >
<xs:annotation>
<xs:documentation>1</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value='Screen Type B' >
<xs:annotation>
<xs:documentation>2</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value='Screen Type C' >
<xs:annotation>
<xs:documentation>3</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<!--============ ScreenResult ============-->
<xs:simpleType name="ScreenResult">
<xs:restriction base='xs:token'>
<xs:enumeration value='1' >
<xs:annotation>
<xs:documentation>Positive</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value='2' >
<xs:annotation>
<xs:documentation>Negative</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value='3' >
<xs:annotation>
<xs:documentation>Not administered</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
I'm posting my solution for anyone else who runs into this problem.
Although I had asserted that all of my namespaces were correct, that was, of course the problem. All of the namespaces were correct except on the unique element itself.
I erroneously assumed that the unique element would not need to prefix a namespace as it was within the context. But that is not the case. Since I did declare a default namespace for the file, I still needed the prefix.
So my only change, and the solution, is as follows:
<xs:element name="ScreenResults" type="import:ScreenResults" minOccurs="0" maxOccurs="1">
<xs:unique name="UniqueScreenResults">
<xs:selector xpath="import:ScreenResult" />
<xs:field xpath="#Type" />
</xs:unique>
</xs:element>

Resources