1

I have difficulty in writing a schema in XSD1.1. XML structure is already defined and used by many teams, so changing the xml is not an option to me. May be I can't explain everything I tried here. XSD has evolved so much since start. I just hope some ppl can understand the problem clearly.. Would be great if someone can share their way of solving this problems..

How XML looks like (in simplified format)

<Node>
    <Create Type="A">
        <Attr Name="Type1" Val="123"/>
        <Attr Name="Type2" Val="Water"/>
        <Attr Name="Type3" Val="2019-12-01T08:00:00"/>
    </Create>
    <Create Type="B">
        <Attr Name="TypeM" Val="OB123"/>
        <Attr Name="Type2" Val="Fire"/>
        <Attr Name="TypeK" Val="2019-12-01T08:00:00"/>
        <Attr Name="TypeN" Val="11.567"/>   
    </Create>
</Node>

Problem:

  1. Based on "Type" attribute in Element<Create> - Number of <Attr> Elements changes (There are 80 types). Each Type can allow specific set of child attr. In above e.g, when Type = A, it can have only 3 children and specifically Type1, Type2 and Type3.

  2. Based on value of "Name" attribute in Element <Attr> , attribute "Val" can have range of Values. In Xml shown above, Type2 can have {Fire, Water}

  3. Based on value of "Name" attribute in Element<Attr> , define the type of second attribute "Val" which can be (date,integer, string, float etc)

The XSD I am trying to write looks something like this (actual XSD and XML are huge)..

<xs:element name="Node" type="NodeType"/>   

    <xs:complexType name="NodeType">
        <xs:sequence>
            <xs:element name="Create">
                <xs:alternative test="@Type = 'A'" type="AType"/>
                <xs:alternative test="@Type = 'B'" type="BType"/> 
                <xs:alternative type="xs:error"/>
            </xs:element>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="AType">
        <xs:sequence>
            <xs:element name="Attr">
                <xs:alternative test="@Name = 'Type1'" type="AttrType1"/>
                <xs:alternative test="@Name = 'Type2'" type="AttrType2"/>
                <xs:alternative test="@Name = 'Type3'" type="AttrType3"/>
                <!--<xs:alternative type="xs:error"/>  This line gives error while same line above passes validation-->
            </xs:element> 
        </xs:sequence>
        <xs:attribute name="Type" use="required" type="AllowedTypes"/> <!-- AllowedTypes is an enum of 80 values-->
        <xs:assert test="(@Type = 'A')"/> 
    </xs:complexType>

    <xs:complexType name="AttrType1">
        <xs:attribute name="Name" type="xs:string"/>
        <xs:attribute name="Val" type="xs:integer"/>
    </xs:complexType>
    <xs:complexType name="AttrType2">
        <xs:attribute name="Name" type="xs:string"/>
        <xs:attribute name="Val" type="xs:string"/>
        <xs:assert test="(@Val = 'Fire' or @Val='Water')"/> 
    </xs:complexType>
    <xs:complexType name="AttrType3">
        <xs:attribute name="Name" type="xs:string"/>
        <xs:attribute name="Val" type="xs:dateTime"/>
    </xs:complexType>

<!-- Similarly written for BType -->

Thanks to this post - How to make type depend on attribute value using Conditional Type Assignment.

After spending days.. I am able to solve 3 problems (one at a time) stated above.. I am facing issue when I tried to club all 3 solutions in one nice compact xsd.

For Eg.. When I try to solve Problem 3, solution to problem 1 is messed up.

<Node>
   <Create Type="A">
        <Attr Name="Type1" Val="123"/>
        <Attr Name="Type2" Val="Water"/>
        <Attr Name="TypeZ" Val="2019-12-01T08:00:00"/>
   </Create>
</Node>
    <!-- I want XSD to throw error saying TypeZ is not allowed  -->   
Vilas M
  • 11
  • 2
  • `xs:assert` doesn't take a `type` attribute. You're thinking of `xs:alternative`, which is a part of [Conditional Type Assignment](https://www.w3.org/TR/xmlschema11-1/#cTypeAlternative), which is the way to go here. For an example, see [How to make type depend on attribute value using Conditional Type Assignment](https://stackoverflow.com/questions/27878402/how-to-make-type-depend-on-attribute-value-using-conditional-type-assignment) – kjhughes Jan 23 '20 at 13:36
  • Thank you for suggestion. Looking at the example shared by you, I was able to solve major problem last week. As mentioned above, I tried both assert and alternative but wasn't successful. I will post what I tried.. Can you please write advise a solution for this too? – Vilas M Jan 23 '20 at 14:49
  • If the provided link and comment doesn't suffice to resolve your problem, [edit] your question and add a *complete* [mcve] illustrating any confusion that remains. – kjhughes Jan 23 '20 at 15:31

1 Answers1

0

I rectified xsd to solve all prob statements


<?xml version="1.0"?>
<xs:schema attributeFormDefault="unqualified" 
           elementFormDefault="qualified" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" 
           xmlns:xerces="http://xerces.apache.org"
           vc:minVersion="1.1">

    <xs:element name="Node" type="NodeType"/>   

    <xs:complexType name="NodeType">
        <xs:sequence>
            <xs:element name="Create" maxOccurs="5">
                <xs:alternative test="@Type = 'A'" type="AType"/>
                <xs:alternative test="@Type = 'B'" type="BType"/> 
                <xs:alternative type="xs:error"/>
            </xs:element>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="AType">
        <xs:sequence>
            <xs:element name="Attr" maxOccurs="3">
                <xs:alternative test="@Name = 'Type1'" type="AttrType1"/>
                <xs:alternative test="@Name = 'Type2'" type="AttrType2"/>
                <xs:alternative test="@Name = 'Type3'" type="AttrType3"/>
                <xs:alternative type="xs:error"/>  
            </xs:element> 
        </xs:sequence>
        <xs:attribute name="Type" use="required" type="xs:string"/>
        <xs:assert test="(@Type = 'A')"/> 
    </xs:complexType>

    <xs:complexType name="AttrType1">
        <xs:attribute name="Name" type="xs:string"/>
        <xs:attribute name="Val" type="xs:integer"/>
    </xs:complexType>
    <xs:complexType name="AttrType2">
        <xs:attribute name="Name" type="xs:string"/>
        <xs:attribute name="Val" type="xs:string"/>
        <xs:assert test="(@Val = 'Fire' or @Val = 'Water')"/> 
    </xs:complexType>
    <xs:complexType name="AttrType3">
        <xs:attribute name="Name" type="xs:string"/>
        <xs:attribute name="Val" type="xs:dateTime"/>
    </xs:complexType>

    <!-- Similarly written for BType -->
    <xs:complexType name="BType">
        <xs:sequence>
            <xs:element name="Attr" maxOccurs="4">
                <xs:alternative test="@Name = 'TypeM'" type="AttrTypeM"/>
                <xs:alternative test="@Name = 'Type2'" type="AttrType2"/>
                <xs:alternative test="@Name = 'TypeK'" type="AttrTypeK"/>
                <xs:alternative test="@Name = 'TypeN'" type="AttrTypeN"/>
                <xs:alternative type="xs:error"/>  
            </xs:element> 
        </xs:sequence>
        <xs:attribute name="Type" use="required" type="xs:string"/>
        <xs:assert test="(@Type = 'B')"/> 
    </xs:complexType>

    <xs:complexType name="AttrTypeM">
        <xs:attribute name="Name" type="xs:string"/>
        <xs:attribute name="Val" type="xs:string"/>
    </xs:complexType>
    <xs:complexType name="AttrTypeK">
        <xs:attribute name="Name" type="xs:string"/>
        <xs:attribute name="Val" type="xs:dateTime"/>
    </xs:complexType>
    <xs:complexType name="AttrTypeN">
        <xs:attribute name="Name" type="xs:string"/>
        <xs:attribute name="Val" type="xs:float"/>
    </xs:complexType>
</xs:schema>

Vilas M
  • 11
  • 2