views:

374

answers:

5

How can I create one XML Schema that will work with multiple but similar XML files. For instance, for a Food Recipes website I have a recipe XML called 'dessert' another 'indian' and another 'vegetarian', they are all pretty much the same, the only thing that changes is the root element. Here's an example of a file:

<?xml version="1.0" encoding="utf-8"?>
<!-- this one could be dessert, indian or vegetarian -->
<dessert id="dessert01" xmlns="http://www.w3schools.com"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="schematize.xsd">
    <category>Dessert</category>
    <headline>Caramelised Bananas and Puff Pastry</headline>
    <thumbnail>http://media.lookandtaste.com/files/video_thumbs/caramelized_banana_on_puff_pastry.jpg&lt;/thumbnail&gt;
    <intro>Most people are terrified of making desserts so this is one
    that I invented to get you all out of that tricky situation...</intro>
    <media>
        <video><![CDATA[
  <object type="application/x-shockwave-flash" data="http://www.lookandtaste.com//web/jwplayer/player.swf" width="480" height="292" ><param name="movie" value="http://www.lookandtaste.com//web/jwplayer/player.swf" /><param name="bgColor" value="#000000" /><param name="allowfullscreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="FlashVars" value="stretching=exactfit&file=http://videos.lookandtaste.com/New_Vids/Caramelised Bananas and Puff Pastry_01.flv&image=http://www.lookandtaste.com/files/video_thumbs/caramelized_banana_on_puff_pastry.jpg"/&gt;&lt;/object&gt;
  ]]>
        </video>
    </media>
    <summary>
        <preparation>10 minutes</preparation>
        <time>20 minutes</time>
        <difficulty>Medium</difficulty>
        <healthy>2</healthy>
    </summary>
    <ingredients>
        <ingredient>Puff pastry</ingredient>
        <ingredient>Bananas</ingredient>
        <ingredient>12 cups of sugar</ingredient>
        <ingredient>Knob of butter</ingredient>
        <ingredient>2 tsp of creme fraiche</ingredient>
        <ingredient>1/2 cup of chocolate</ingredient>
    </ingredients>
    <procedures>
        <step>Peel the bananas and chop into chunks. Put the butter and
        bananas in a pan over a medium heat and sprinkle with sugar.
        Caramelise for 4-5 minutes moving the ingredients every few minutes.</step>
        <step>Meanwhile sprinkle flour onto a baking tray and also
        onto a clean flat surface. Roll your pastry on the surface and then
        cut out a circle shape using the top of a bowl as a cutter.</step>
        <step>Put the pastry on the floured baking tray and prick the
        pastry with a fork. Put the pastry into the over for 12-15 minutes at
        180c/360f.</step>
        <step>The bananas should be caramelised now so take them off the
        heat and set them aside.</step>
        <step>Take the pastry out of the oven once it is ready and pile
        the bananas on top with some creme fraiche. Drizzle with melted
        chocolate and serve.</step>
    </procedures>
    <keywords>banana hot caramel dessert</keywords>
</dessert>

... And here is my XML Schema file:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified">
    <xs:element name="dessert">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="category"/>
                <xs:element ref="headline"/>
                <xs:element ref="thumbnail"/>
                <xs:element ref="intro"/>
                <xs:element ref="media"/>
                <xs:element ref="summary"/>
                <xs:element ref="ingredients"/>
                <xs:element ref="procedures"/>
                <xs:element ref="keywords"/>
            </xs:sequence>
            <xs:attribute name="id" use="required" type="xs:NCName"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="category" type="xs:NCName"/>
    <xs:element name="headline" type="xs:string"/>
    <xs:element name="thumbnail" type="xs:anyURI"/>
    <xs:element name="intro" type="xs:string"/>
    <xs:element name="media">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="video"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="video" type="xs:string"/>
    <xs:element name="summary">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="preparation"/>
                <xs:element ref="time"/>
                <xs:element ref="difficulty"/>
                <xs:element ref="healthy"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="preparation" type="xs:string"/>
    <xs:element name="time" type="xs:string"/>
    <xs:element name="difficulty" type="xs:NCName"/>
    <xs:element name="healthy" type="xs:integer"/>
    <xs:element name="ingredients">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="unbounded" ref="ingredient"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="ingredient" type="xs:string"/>
    <xs:element name="procedures">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="unbounded" ref="step"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="step" type="xs:string"/>
    <xs:element name="keywords" type="xs:string"/>
</xs:schema>

Pointers to possible solution or how to approach it will be greatly appreciated. Thanks in advance!

+1  A: 

You need to specify "choice" indicator while writing schema for root element. since most of the contents are common for all root elements, you can define one complex type and then reuse to avoid writing them again. Refer http://www.w3schools.com/schema/schema_complex_indicators.asp

[EDIT]

If you can control the XML document structure (i.e. if they are not used by other applications), why not define a root element named "food" and specify the possible attribute foodType having values such as "desert" and "indian".

Hemant
+2  A: 

Isn't that just:

<xs:complexType name="food">...</xs:complexType>
<xs:element type="food" name="dessert"/>
<xs:element type="food" name="indian"/>
Marc Gravell
A: 

Here's one approach:

Change the schema element to something like:

<xs:schema xmlns="urn:my.nampespace"
    targetNamespace="urn:my.nampespace"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified">

Change the first element to something like:

<xs:element name="dessert" type="recipeType"/>
<xs:element name="indian" type="recipeType"/>
<xs:complexType name="recipeType">
    <xs:sequence>
        <xs:element ref="category"/>
        <xs:element ref="headline"/>
        <xs:element ref="thumbnail"/>
        <xs:element ref="intro"/>
        <xs:element ref="media"/>
        <xs:element ref="summary"/>
        <xs:element ref="ingredients"/>
        <xs:element ref="procedures"/>
        <xs:element ref="keywords"/>
    </xs:sequence>
    <xs:attribute name="id" use="required" type="xs:NCName"/>
</xs:complexType>

Now you can define your xml like:

<dessert id="dessert01"
    xmlns="urn:my.nampespace" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
    xsi:schemaLocation="urn:my.nampespace recipe.xsd">

Or:

<indian id="indian01" 
    xmlns="urn:my.nampespace" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="urn:my.nampespace recipe.xsd">
toolkit
A: 

What about kulfi? (a vegetarian, Indian dessert)

You probably shouldn't be varying the root element, but adding attributes to indicate categories.

Pete Kirkham
A: 

@Hemant & @Pete Kirkham: I think what you guys say makes more sense. I'll try to modify my files as such.

@toolkit: Your suggestion worked very nicely with how I had set up my files.

Many thanks guys! Very insightful and helpful.

Ivanico