Search code examples
xmlxpathassertrestrictionxsd-1.1

XML element restriction using XPath query in XSD1.1 assert


I wrote "music.xsd" for validating the below "music.xml" file. In the music file there are two specializations styleSpec and ensembleSpec.

 <specialization name="styleSpec">
    <entity name="Symphonic">
    </entity>    
 </specialization>

and

 <specialization name="ensembleSpec">
    <entity name="Orchestra">
    </entity>   
 </specialization>

"styleSpec" permitted entities are Symphonic, Folk and Jazz.

"ensembleSpec" permitted entities are Orchestra, SmallGroup and Soloist.

I want to add the following restrictions:

  1. if the entity inside styleSpec is Symphonic then the entity inside ensembleSpec must be Orchestra.

  2. if the entity inside styleSpec is Folk then the entity inside ensembleSpec must be either SmallGroup or Soloist.

  3. if the entity inside styleSpec is Jazz then the entity inside ensembleSpec must be either Orchestra or SmallGroup.

I am able to do this in another XSD file (another.xsd,given below) but when i add that assert statement in music.xsd it is not working.

How can i solve this problem?

music.xml

<?xml version="1.0" encoding="UTF-8"?>
<entity xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="music.xsd" 
 name="MusicPerformances"> 

<multiAspect name="musicPerformancesMAsp">
 <entity name="MusicPerformance">

 <specialization name="styleSpec">
  <entity name="Symphonic">
  </entity>    
 </specialization>

 <specialization name="ensembleSpec">
  <entity name="Orchestra">
  </entity>   
 </specialization>

 </entity>
</multiAspect> 

</entity>    

music.xsd

<?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:complexType name="aspectType">
    <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" ref="entity"/>
    </xs:sequence>
    <xs:attribute name="name" use="required"/>
</xs:complexType>

<xs:complexType name="multiAspectType">
    <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" ref="entity"/>
    </xs:sequence>
    <xs:attribute name="name" use="required"/>
</xs:complexType>

<xs:complexType name="specializationType">
    <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" ref="entity"/>
    </xs:sequence>
    <xs:attribute name="name" use="required"/>
</xs:complexType>


<xs:complexType name="varType"> 
    <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" ref="entity"/>
    </xs:sequence>
    <xs:attribute name="name" use="required"/>

</xs:complexType>


<xs:element name="entity">
    <xs:complexType>
        <xs:sequence>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element ref="aspect"/>
                <xs:element ref="specialization"/>
                <xs:element ref="multiAspect"/>
                <xs:element ref="var"/>

            </xs:choice>            

        </xs:sequence>

        <xs:attribute name="name" use="required"/>

        <xs:assert test="every $x in .//entity satisfies empty($x//*[@name = $x/@name])"/>
        <!--   

        <xs:assert test=
            **// Maybe have to add XPath query here. But I am not sure where 
              i will add.**
        />

          --> 
    </xs:complexType> 

    <xs:unique name="entityunqall">
        <xs:selector xpath="*/entity"/>            
        <xs:field xpath="@name"/>
    </xs:unique> 


</xs:element>

<xs:element name="aspect" type="aspectType"/>
<xs:element name="multiAspect" type="multiAspectType"/>
<xs:element name="specialization" type="specializationType"/>
<xs:element name="var" type="varType"/>   

The another.xml file is working with another.xsd properly.

another.xsd

<?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="styleSpec">       
    <xs:simpleType>
        <xs:restriction base="xs:string">
            <xs:enumeration value="Symphonic" />
            <xs:enumeration value="Folk" />
            <xs:enumeration value="Jazz" />
        </xs:restriction>
    </xs:simpleType>
</xs:element> 

<xs:element name="ensembleSpec">       
    <xs:simpleType>
        <xs:restriction base="xs:string">
            <xs:enumeration value="Orchestra" />
            <xs:enumeration value="SmallGroup" />
            <xs:enumeration value="Soloist" />
        </xs:restriction>
    </xs:simpleType>
</xs:element>

<xs:element name="MusicalPerformance">
    <xs:complexType>
        <xs:sequence>                 
            <xs:element ref="styleSpec"/>
            <xs:element ref="ensembleSpec"/>                      
        </xs:sequence>
        <xs:assert test="(styleSpec = 'Symphonic' and ensembleSpec=('Orchestra'))
            or
            (styleSpec = 'Folk' and ensembleSpec=('SmallGroup','Soloist'))
            or
            (styleSpec = 'Jazz' and ensembleSpec=('Orchestra','SmallGroup'))
            "/>
    </xs:complexType>
</xs:element>



</xs:schema>

another.xml

<?xml version="1.0" encoding="UTF-8"?>
<MusicalPerformance xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="another.xsd">
    <styleSpec>Folk</styleSpec>
    <ensembleSpec>Soloist</ensembleSpec>     
</MusicalPerformance>

Edit

I have changed the music file and new file is given below:

music.xml

<?xml version="1.0" encoding="UTF-8"?>
<entity xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="musicalperformances.xsd" 
name="MusicPerformances">

  <multiAspect name="MusicPerformancesMAsp">
  <entity name="MusicPerformance">
  <aspect name="MusicPerformanceDec">
    <entity name="Music">
      <specialization name="styleSpec">
        <entity name="Jazz">
        </entity>
      </specialization>
    </entity>
    <entity name="Performer">
      <specialization name="ensembleSpec">
        <entity name="SmallGroup">
        </entity>
      </specialization>
    </entity>
  </aspect>
  </entity>
  </multiAspect>


  </entity>

Solution

  • Firstly, the assertion needs to go on the parent element of the two specialization elements (i.e. at the level of the multiAspect element). You haven't made it clear in your question or in your comments where you put the assertion, which may indicate that you haven't realised how important it is to get this right.

    The rules are then very simple, for example:

    if the entity inside styleSpec is Symphonic then the entity inside ensembleSpec must be Orchestra.

    test="if (specialization[@name='styleSpec']/entity/@name='Symphonic')
          then specialization(@name='ensembleSpec']/entity/@name='Orchestra' 
          else true()"