How to define an appropriate complex type? - xsd

I have this in my xsd:
<xs:element name="Parameter" type="complex">
and I want to define complex like:
<xs:simpleType name="complex">
1 xs:decimal
2 xs:string
</xs:simpleType>
So if the value for Parameter is decimal to take decimal and if value is not decimal to assume that value is string. How to declare my complex type?

You'll need a complexType together with a choice to express this:
<xs:complexType name="complex">
<xs:choice>
<xs:element name="number" type="xs:decimal"/>
<xs:element name="string" type="xs:string"/>
</xs:choice>
</xs:complexType>
Edit: Based on your comments maybe this is worth a try:
<xs:simpleType name="monat">
<xs:union memberTypes="xs:decimal xs:string"/>
</xs:simpleType>
But JAXB will translate this to String anyway, so there's no benefit from the union, at least with respect to the generated classes. And that you are using JAXB is just a guess.

Related

XSD: restrict attribute to xs:float or ""

I'm trying to define an element type in XSD, for which i want an optional attribute, which if present can either contain a float, or be empty (but still present).
i.e:
<xs:element name="MyElement">
<xs:complexType>
<xs:attribute name="optionalFloatAttribute" type="xs:float" use="optional"/>
</xs:complexType>
</xs:element>
Needs "fixing" to allow all of the following xml:-
<MyElement/>
or
<MyElement optionalFloatAttribute=""/>
or
<MyElement optionalFloatAttribute="3.14159"/>
The only way I can see of doing this is to change type to xs:string, and use xs:restriction with a regular expression. But this doesn't seem very ideal to me. Is there a better way?
And I have to be able to support these variations of the xml - the program and existing xml is legacy, and I am trying to back-create a schema to match the myriad variations I see in what we have to regard as valid xml.
You can define custom type for that by combining float and empty string:
<xs:element name="MyElement">
<xs:complexType>
<xs:attribute name="optionalFloatAttribute" type="emptyFloat" use="optional"/>
</xs:complexType>
</xs:element>
<xs:simpleType name="emptyFloat">
<xs:union>
<xs:simpleType>
<xs:restriction base='xs:string'>
<xs:length value="0"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction base='xs:float'>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
Or using regExp:
<xs:simpleType name="emptyFloat">
<xs:restriction base="xs:string">
<xs:pattern value="-?\d*\.?\d*"/>
</xs:restriction>
</xs:simpleType>
If you could stand using an element rather than an attribute you could make the xs:float nillable. This way you can use the xsi:nil="true" in your instance document to indicate that the element has no value:
<!-- definition -->
<xs:element name="quantity" type="xs:float" nillable="true" />
<!-- instance -->
<quantity xsi:nil="true" />
No equivalent for attributes though.
I don't think there's a way to handle this and use xs:float. Fundamentally it comes down to the fact that empty string isn't a valid number. You'd either normally expect a value of 0, or for the element to be missing altogether. There's a good explanation as the answer to the following question:
Empty elements for primitve datatypes forbidden in XSD
It seems that the option of using xs:string and a regexp might be your best plan.

Is this the proper way to added enumerated attributes to a complexType?

Is this the proper way to set an attribute with enumerated values on the complexType AvailStatusMessageType. I see a lot of examples that declare a complexContent section right below the complexType declaration? What is this complexContent for and is it necessary here?
<xs:complexType name="AvailStatusMessageType">
<xs:sequence>
<xs:element name="LengthsOfStay" type="LengthsOfStayType" />
<xs:element name="RestrictionStatus" type="RestrictionStatusType"/>
</xs:sequence>
<xs:attribute name="BookingLimit">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="SetLimit" />
<xs:enumeration value="AdjustLimit"/>
<xs:enumeration value="RemoveLimit"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
Element types can be divided into two categories in XML Schemas
Elements that can contain structural markup (attributes or child elements)
Elements that contain only textual markup
Further, the elements that contain markup (group 1) can be again divided to two groups
Elements that are allowed to have child elements
Elements that are not allowed to have child elements
First division separates (1) <complexType> and (2) <simpleType>. Second one separates (1) <complexContent> and (2) <simpleContent>.
<xs:complexContent> is not usually seen, because it is an implicit default so the whole structure can be abbreviated by omitting that element. This common structure
<xs:complexType>
... (<xs:sequence> or anything) ...
</xs:complexType>
is actually identical to
<xs:complexType>
<xs:complexContent>
<xs:restriction base="xs:anyType">
... (<xs:sequence> or anything) ...
</xs:restriction>
</xs:complexContent>
</xs:complexType>
In your structure an element with type "AvailStatusMessageType" 1) contains markup 2) and has child elements. So your structure is a complex type with complex content. Your example seems correct even though you haven't used the <xs:complexContent> element, because you are actually using the abbreviated form. It is identical to this:
<xs:complexType name="AvailStatusMessageType">
<xs:complexContent>
<xs:restriction base="xs:anyType">
<xs:sequence>
<xs:element name="LengthsOfStay" type="LengthsOfStayType" />
<xs:element name="RestrictionStatus" type="RestrictionStatusType"/>
</xs:sequence>
<xs:attribute name="BookingLimit">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="SetLimit" />
<xs:enumeration value="AdjustLimit"/>
<xs:enumeration value="RemoveLimit"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
A complex type may have simple or complex content. You would use <simpleContent> if you were defining a complex type with simple content. You must use the <complexContent> element when you are restricting or extending another complex type (because you specify the base type as an attribute in the <complexContent> element). If you are simply creating a complex type (with complex content), as you are doing, you may use (but are not required to use) the <complexContent> element.
Your enumeration looks right.

How to define a Constant in XSD

Is there a way to define a constant value and use that constant in the preceeding XSD? I have a common value I want to use for various xs:element tag's maxOccurs attributes. Like constants in other languages, I want to make the change in one place should the value backing MyConst were to ever change.
<!-- Can I do this? -->
<ConstantValue id="MyConst" value="10"/>
...
<xs:element name="sandwich_meat" type="xs:string" minOccurs="0" maxOccurs="MyConst"/>
<xs:element name="sandwich_name" type="xs:string" minOccurs="0" maxOccurs="MyConst"/>
You can try to define a simpleType with a restriction:
<xs:simpleType name="AConstantHere">
<xs:restriction base="xs:string">
<xs:enumeration value="CONSTANT_VALUE_HERE"/>
</xs:restriction>
</xs:simpleType>
It allows only one value.
No it is not allowed that way. However you can define your own type with a fixed value in it somewhere on top of your XSD (place dosen matters) and use that type for the elements.
It's not possible with plain schema, but maybe XML entities will do the trick?

distincting xs:choices in xsd by using fixed values for element with enumeration type

Is it possible to distinct xs:choices in xsd by using fixed values? I have a simple type:
<xs:simpleType name="datatypeCategory">
<xs:restriction base="xs:string">
<xs:enumeration value="SIMPLE"/>
<xs:enumeration value="COMPLEX"/>
<xs:enumeration value="COLLECTION"/>
</xs:restriction>
</xs:simpleType>
And what I want to achieve is
<xs:element name="datatype">
<xs:complexType>
<xs:choice>
<xs:sequence>
<xs:element id="category" type="datatypeCategory" fixed="SIMPLE"/>
<!-- some fields specific for SIMPLE -->
</xs:sequence>
<xs:sequence>
<xs:element id="category" type="datatypeCategory" fixed="COMPLEX"/>
<!-- some fields specific for COMPLEX -->
</xs:sequence>
<xs:sequence>
<xs:element id="category" type="datatypeCategory" fixed="COLLECTION"/>
<!-- some fields specific for COLLECTION -->
</xs:sequence>
</xs:choice>
</xs:complexType>
</xs:element>
When I do this my XMLSpy tells me:
# The content model of complex type definition '{anonymous}' is ambiguous.
# Details: cos-nonambig: <xs:element name='category'> makes the content model non-deterministic against <xs:element name='category'>. Possible causes: name equality, overlapping occurrence or substitution groups.
You can't do exactly that. The error is because a simple validator that sees a <category> element won't immediately know which branch of the choice to take, and XML Schema 1.0 supports such simple validators.
An alternative would be to name each element according to the category.
<xs:element name="datatype">
<xs:complexType>
<xs:choice>
<xs:sequence>
<xs:element name="simpleCategory" type="empty"/>
<!-- some fields specific for SIMPLE -->
</xs:sequence>
<xs:sequence>
<xs:element name="complexCategory" type="empty"/>
<!-- some fields specific for COMPLEX -->
</xs:sequence>
<xs:sequence>
<xs:element name="collectionCategory" type="empty"/>
<!-- some fields specific for COLLECTION -->
</xs:sequence>
</xs:choice>
</xs:complexType>
</xs:element>
where empty is defined as an empty type. Or give them complex types to hold the "specific fields". There are other alternatives depending on your constraints, such as using substitution groups or derived complex types.
In general though, XML Schema 1.0 is not good for constraints based on interrelated values. For that, you have to go to XML Schema 1.1 or an external tool.
IDs must be unique within a document. You can't use the same value on multiple elements:
http://www.w3.org/TR/2006/REC-xml11-20060816/#id

Schema Issue: Can define element type OR add element attribute, but not both. I want both!

I've inherited the task of creating a schema for some XML which already exists - and IMHO is not the best that could have been done. The section giving me problems is the element at the end of the 'scan-result' element.
The best I'm hoping for with regard to the data in the 'spectrum' element is to treat it as type="xs:string". I'll programatically divide up the numeric pairs that constitute the data in the string later. (Even though this step would not be needed had the data been properly structured in the first place.)
Here's a similar piece of XML data to what I have to work with...
<scan-result>
<spectrum-index>0</spectrum-index>
<scan-index>2</scan-index>
<time-stamp>5609</time-stamp>
<tic>55510</tic>
<start-mass>22.0</start-mass>
<stop-mass>71.0</stop-mass>
<spectrum count="5">30,11352;31,360;32,16634;45,1161;46,26003</spectrum>
</scan-result>
The problem is, I can't seem to get a working definition for the 'spectrum' element that has the 'count' attribute and allows me to define the 'spectrum' element type as "xs:string".
What I would like is something like the following:
<xs:complexType name="ctypScanResult">
<xs:sequence>
<xs:element name="spectrum-index" type="xs:integer"/>
<xs:element name="scan-index" type="xs:integer"/>
<xs:element name="time-stamp" type="xs:integer"/>
<xs:element name="tic" type="xs:integer"/>
<xs:element name="start-mass" type="xs:float"/>
<xs:element name="stop-mass" type="xs:float"/>
<xs:element name="spectrum" type="xs:string">
<xs:complexType>
<xs:attribute name="count" type="xs:integer"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="count" type="xs:integer"/>
</xs:complexType>
The problem is that I can define the type of the 'spectrum' element as "xs:string" XOR I can define the anonymous 'xs:complexType' in the 'spectrum' element, which allows me to insert the 'count' attribute. But I need to be able to express both.
Given that I'm kind of stuck with the XML as it was handed to me, is there a schema definition that will allow me to describe this data?
Sorry this is long, but thanks to any and all who respond,
AlarmTripper
Followup: I know why the error occurs...
Quoted from W3C:
3.3.3 Constraints on XML Representations of Element Declarations
Schema Representation Constraint: Element Declaration Representation OK
In addition to the conditions imposed on element information items by the schema for schemas: all of the following must be true:
1 default and fixed must not both be present.
2 If the item's parent is not , then all of the following must be true:
2.1 One of ref or name must be present, but not both.
2.2 If ref is present, then all of , , , , , nillable, default, fixed, form, block and type must be absent, i.e. only minOccurs, maxOccurs, id are allowed in addition to ref, along with .
3 type and either or are mutually exclusive.
4 The corresponding particle and/or element declarations must satisfy the conditions set out in Constraints on Element Declaration Schema Components (§3.3.6) and Constraints on Particle Schema Components (§3.9.6).
But I'm still in the same fix I was before... How can I actually accomplish something that resembles my goal?
Thanks,
AlarmTripper
Let a tool do it for you! Try xsd.exe.
Or, if you must define by hand, at least check your hand-written-definition with an automatically generated one.
Here's what XSD.exe gave me for your input. I trimmed out some MS-NS cruft.
<xs:element name="spectrum">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="count" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
You need to set the attribute mixed="true" on complexType:
<xs:element name="spectrum">
<xs:complexType mixed="true">
<xs:attribute name="count" type="xs:integer" />
</xs:complexType>
</xs:element>
EDIT: Okay, just read your comment, sorry. I believe the following should work instead:
<xs:element name="spectrum">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="count" type="xs:integer" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="spectrum" type="xs:string">
<xs:complexType>
<!-- ADD THIS NEXT LINE -->
<xs:complexContent mixed="true"/>
<xs:attribute name="count" type="xs:integer"/>
</xs:complexType>
</xs:element>

Resources