Uploading XSD schemas with imported namespaces into Marklogic 6 - xsd

As a small excercise I'm trying to upload and validate documents with a couple of schemas. These will eventually grow so I'd like to keep them separate.
These example schemas define a localized text string and a food dish:
bitfood-common.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:bfc="http://bitfood.org/common"
targetNamespace="http://bitfood.org/common"
elementFormDefault="qualified">
<xs:simpleType name="objectId">
<xs:restriction base="xs:string">
<xs:length value="24"/>
<xs:whiteSpace value="collapse"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="locale">
<xs:restriction base="xs:string">
<xs:length value="5"/>
<xs:whiteSpace value="collapse"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="localizedText">
<xs:attribute name="text" type="xs:string" use="required"/>
<xs:attribute name="locale" type="bfc:locale" use="required"/>
</xs:complexType>
</xs:schema>
bitfood-dish.xsd:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:bfd="http://bitfood.org/dish"
xmlns:bfc="http://bitfood.org/common"
targetNamespace="http://bitfood.org/dish"
elementFormDefault="qualified">
<xs:import namespace="http://bitfood.org/common"
schemaLocation="../common/bitfood-common.xsd" />
<xs:element name="Dish">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="bfc:localizedText" maxOccurs="unbounded"/>
<xs:element name="description" type="bfc:localizedText" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="id" type="bfc:objectId" use="required"/>
<xs:attribute name="price" type="xs:decimal" use="required"/>
<xs:attribute name="imageUrl" type="xs:anyURI" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
I then uploaded these two documents inside the Schemas database assigned to my xml database with the following URI id's:
schema/common/bitfood-common.xsd
schema/dish/bitfood-dish.xsd
And then I uploaded an example document:
dish/520cc720c208c01ddfb75254.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Dish id="520cc720c208c01ddfb75254" price="35"
imageUrl="FoodCantonGourrmetTwoDish.jpg"
xmlns="http://bitfood.org/dish">
<name text="Example dish." locale="en-US"/>
<description text="Localized text test." locale="en-US"/>
</Dish>
When I issue the following command on the server's query console, I get the empty set when I instruct the database to infer the type of the xml document's root node:
Update: wrong node index, must be 1 in this case:
(: is it working? :)
declare namespace bfd = "http://bitfood.org/dish";
declare namespace bfc = "http://bitfood.org/common";
xdmp:describe(data(
doc('dish/520cc720c208c01ddfb75254.xml')/bfd:Dish[1]
))
Output:
<?xml version="1.0" encoding="UTF-8"?>
<results warning="atomic item">xs:untypedAtomic("")</results>
This means that the database is either ignoring or not able to find my schema documents. Also, I am not sure if it can't apply the schemas because of the xs:import namespace statement.
Has anyone attempted to work with imported XSD documents into Marklogic in this way? Is there anything I may be doing wrong?
Update 2: It seems this can only be applied to attributes. The following command does work as expected, which means the schemas are being detected:
(: is it working? :)
declare namespace bfd = "http://bitfood.org/dish";
declare namespace bfc = "http://bitfood.org/common";
xdmp:describe(data(doc('dish/520cc720c208c01ddfb75254.xml')/bfd:Dish[1]/#id))
Thanks!

XQuery positional predicates start at 1 not 0.
Try this:
doc('dish/520cc720c208c01ddfb75254.xml')/bfd:Dish[1]
Then work your way up to more complicated code.
-David Lee

Related

Including / importing local schemas that have namespaces

Here is a schema file, midi.xsd that defines a type, note, used to store MIDI note values:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="note">
<xs:restriction base="xs:integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="127"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
Here is another schema file, octaves.xsd which uses midi.xsd to help define the layout to be enforced on an XML file containing data about octaves:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:include schemaLocation="midi.xsd"/>
<xs:element name="octaves">
<xs:complexType>
<xs:sequence>
<xs:element name="octave">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string" />
<xs:element name="midi">
<xs:complexType>
<xs:sequence>
<xs:element name="value" type="xs:integer" />
<xs:element name="from" type="note" />
<xs:element name="to" type="note" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="index" type="xs:integer" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
This is fine, and works exactly as you would expect it to, except that I have another requirement: I want note to be in its own namespace, midi, so that
<xs:element name="from" type="note" />
becomes
<xs:element name="from" type="midi:note" />
Try as I might, I cannot get this to work. My attempts have included use of the targetNamespace attribute in various places, the import element, and liberal use of xmlns:midi="...", but to no avail. I'd post one of these attempts here, were it not so cringe-worthy.
Could some kind soul point me in the right direction? I'm pretty sure the problem is to do with the fact that midi.xsd is a local file; it has never been, and never will be, hosted on a web server.
Change midi.xsd to be:
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetnamespace="/my/midi/namespace">
And then change octaves.xsd to say:
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:midi="/my/midi/namespace">
<xs:import namespace="/my/midi/namespace" schemaLocation="midi.xsd"/>
...
<xs:element name="from" type="midi:note" />
Note the use of xs:import rather than <xs:include> The two are very different - you use import for bringing in other namespaces, and include for inline inclusion of other schema files into the current namespace.
Note also that /my/midi/namespace can be anything you want, it's an arbitrary identifier.
I'm pretty sure the problem is to do with the fact that midi.xsd is a local file
Nope, not relevant.

XML Schema Question

Is it possible to define an XML Schema (XSD) to correctly describe a document such as the following?
<root>
<str name="status">success</str>
<str name="message">Your request has been processed successfuly.</str>
</root>
The problem might be that the <str> tags have an attribute (name) as well as string values.
I would be grateful if anyone could come up with an XML Schema for this piece of XML, since I am kind of stuck at this point. My best attempt so far is shown below, but botice that the <str> element cannot have a type (such as xsd:string) in this context.
<xs:element name="object">
<xs:complexType>
<xs:sequence>
<xs:element name="str" minOccurs="2" maxOccurs="2">
<xs:complexType>
<xs:sequence>
<xs:element name="productName" type="xs:string"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
Your constraints are not entirely clear, so a number of schemas would validate the XML depending on how loose/tight you would want the validation to be. This example shows a schema that mandates exactly two elements inside the element and they must have a "name" attribute with the values "status" or "message".
<?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="str" type="StrType" minOccurs="2" maxOccurs="2"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="StrType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="name" type="StrAttribute" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="StrAttribute">
<xs:restriction base="xs:string">
<xs:enumeration value="status"/>
<xs:enumeration value="message"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
Of course, this would allow two elements both with the name attribute set to "message", or with "message" first, then status. I believe the schema cannot define a sequence containing two elements of the same name but different types which you would need if you required the validation to ensure that the first always contained "status" and the second one contained "message".

XML schema and problem when deriving from mixed type

I have following XML schema:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="content" type="contentType"/>
<xs:complexType name="contentType">
<xs:complexContent>
<xs:extension base="versionedElementType">
<xs:sequence>
<xs:element name="item" type="itemType" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="itemType" mixed="true">
<xs:complexContent>
<xs:extension base="itemTypeBase">
<xs:sequence>
<xs:element name="order" type="xs:unsignedInt"/>
<xs:element name="id" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!-- Simple type convert to complex type -->
<xs:complexType name="itemTypeBase" mixed="true">
<xs:simpleContent>
<xs:extension base="itemDescriptionType">
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- Simple type -string restriction -->
<xs:simpleType name="itemDescriptionType" >
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="64"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="versionedElementType">
<xs:attribute name="version" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>
which I use to validate this XML instance (I want to mix the text in the 'item' element with sub-elements 'order' and 'id'):
<?xml version="1.0" encoding="UTF-8"?>
<content xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Content.xsd"
version ="1.0">
<item>Description here...
<order>2</order>
<id>2</id>
</item>
</content>
Whatever I did the validation still says taht there is an error:
The content type of a derived type and that of its base must both be mixed or both be element-only. Type 'itemType' is mixed, but its base type is not.
But I can see that both types - itemType and itemTypeBase are MIXED!!
Thanks a lot
STeN
First of all the error which I see if I open your schema in Visual Studio 2010 is:
The derived type and the based type
must have the same content type.
In you current schema the type itemTypeBase is defined with respect of the <xs:simpleContent> and derived type itemType with the respect of <xs:complexContent> which is not allowed. Either you allow no sub-elements and use <xs:simpleContent> or you do use child elements and use <xs:complexContent>.
I personally don't like and don't use mixed types. If I understand you correct you want to make some restrictions in the text from the content. You want to have the content length between 1 and 64 characters. But <order>2</order>, <id>2</id> and all whitespace, inclusive the new line characters, are also a part of the content. If you want that <item> has simple content, then you can not insert child elements inside.
So the pragmatical solution would be go away from the mixed model and use the XML document in the form
<?xml version="1.0" encoding="utf-8"?>
<content xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Content.xsd"
version ="1.0">
<item>
<description>Description here...</description>
<order>2</order>
<id>2</id>
</item>
</content>
where Content.xsd is
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="content" type="contentType"/>
<xs:complexType name="contentType">
<xs:sequence>
<xs:element name="item" type="itemType"
minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="version" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="itemType">
<xs:sequence>
<xs:element name="description" type="itemDescriptionType"/>
<xs:element name="order" type="xs:unsignedInt"/>
<xs:element name="id" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="itemDescriptionType" >
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="64"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
All will be very simple and clear.

How to validate empty string value tag in xsd

I have an xml file which is having some date values and other datatypes.
<Purchasedate Name="purcaseDate" value=""/>
I am validating these xml files with a xsd file.
In xsd shcema I have written a regular expression pattern for dd/mm/yyyy format.
This is working fine if value attribute have a value.
My pattern is validating against the value attribute.
The field (purchasedate) is not mandatory.
if value="", this means my pattern is validating against an empty string also, which is not mandatory.
I need to validate the optional field
and i am using <xs:attribute name="PurchaseDate" use="optional"> also.
I need to validate this field when value tag is not empty.
That's too easy ..
Just all you have to do is to include empty string specification in your pattern
This is the way to do that ..
<xs:pattern value="|(Regular_pattern_goes_here)"/>
For your reference I have written a sample chunks of codes .. just go through them ..
sample XML:
<?xml version="1.0" encoding="utf-8"?>
<xmln xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com XMLFile1.xsd" xmlns="http://www.xsdef.com/xml/123">
<Purchasedate Name="purcaseDate" value=""/>
</xmln>
sample XSD:(includes custom type def)
<xs:schema xmlns:xsLocal="http://www.xsdef.com/xml/123" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.xsdef.com/xml/123" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="xmln">
<xs:complexType>
<xs:sequence>
<xs:element name="Purchasedate">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="value" type="xsLocal:CUSTOM_DATE" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="CUSTOM_DATE">
<xs:restriction base="xs:string">
<xs:pattern value="|((01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31)/(01|02|03|04|05|06|07|08|09|10|11|12)/[1-2][0-9][0-9][0-9])"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
try adding this attribute nillable="true" into the xml tag definition
Also you can take a look at his link http://www.zvon.org/xxl/XMLSchemaTutorial/Output/ser_over_st0.html
Best Reagds,
Iordan
The '?' character in the Regex means that the character before it must occur 0 or 1 times.
So in order to solve your issue you need to wrap the regex in parenthesis and put a questionmark at the end:
<xs:simpleType name="PurchaseDateType">
<xs:restriction base="xs:string">
<xs:pattern value="(Regular_pattern_goes_here)?"/>
</xs:restriction>
</xs:simpleType>
Use this type on your field and you should be fine
If you control the syntax of the XML, you should consider defining the element as follows. Since XML-Schema already provides a date type, you should use it unless you have a really good reason. I say this because it will make it easier for others to use the xml and for you to use better code frameworks later. I didn't include the "name" attribute because it seemed redundant to the element name.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="Purchasedate" nillable="true" type="xs:date"/>
<xs:element name="Purchasedate2">
<xs:complexType>
<xs:attribute name="value" type="xs:date"/>
</xs:complexType>
</xs:element>
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element ref="Purchasedate"/>
<xs:element minOccurs="0" ref="Purchasedate2"/>
</xs:sequence>
</xs:complexType>
</xs:element>

XML Schema - only one element should have attribute set to true

How can i define an boolean attribute that can be set "true" only in one element.
Following snippet must be invalid.
<products>
<product featured="yes">Prod 1</product>
<product featured="yes">Prod 2</product>
</products>
You can't do that with XML Schemas.
You can define attributes on an element, but not limit them to one instance of the element.
You could add an attribute in products element indicating which product is featured.
You can't do this with XMLSchema. If you want to specify these constraints in an XML environment try Schematron (http://www.schematron.com/).
You could do the following...
<products>
<product featured="Yes">Prod 1</product>
<product>Prod 2</product>
</products>
Then use a unique element to constrain the attribute thus...
<xs:unique name="UniqueFeaturedProduct">
<xs:selector xpath="product"/>
<xs:field xpath="#featured"/>
</xs:unique>
If you were to restrict the 'featured' attribute to an optional enumeration of one value "Yes" then there could only be one featured attribute. Something like this...
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="products">
<xs:complexType>
<xs:sequence>
<xs:element name="product" type="productType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:unique name="UniqueFeaturedProduct">
<xs:selector xpath="product"/>
<xs:field xpath="#featured"/>
</xs:unique>
</xs:element>
<xs:simpleType name="featuredType">
<xs:restriction base="xs:string">
<xs:enumeration value="Yes"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="productType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="featured" type="featuredType" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
My reply is this way, 'cause I cannot add comments yet.
"You could add an attribute in products element indicating which product is featured."
This solution lead to another problem: checking if the attribute points to existing element.
<products featured_id="3">
<product id="1">Prod 1</product>
<product id="2">Prod 2</product>
</products>

Resources