Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Traceability with XSD

I am trying to let my XML schema handle a little traceability functionality as I'm gathering requirements while I read through some functional specifications. (Not ideal for requirement management, but at least its a start.)

What I'm doing is creating a <functionalSpec> tag for each functional specification I am currently reading through. I create a <requirement> tag for each requirement I find. Since I want to be able to trace where the requirement came from, I create a <trace> element with the id of the <functionalSpec> element. Instead of allowing myself to enter any plain-old-text in the <functionalSpecId> tag, I want the XSD to validate and make sure that I only enter in an id that exists for an existing functional spec. My problem is coming in where it seems the XML Schema W3C Recommendations documentation says that what I want to do is not possible. (about 1/2 way down)

{selector} specifies a restricted XPath ([XPath]) expression relative to instances of the element being declared. This must identify a node set of subordinate elements (i.e. contained within the declared element) to which the constraint applies.

I'm using Oxygen to create this since I'm fairly new to XSD files, and it gives me the following error:

E [Xerces] Identity Constraint error: identity constraint "KeyRef@1045a2" has a keyref which refers to a key or unique that is out of scope.

So my question is does anyone know of a way that will allow me to use the same XML structure that I have below through using XSD?

Below is the XML file.

<?xml version="1.0" encoding="UTF-8" ?>

<srs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="srs req2.xsd"
    xmlns="srs">

<requirements>

<requirement DateCreated="2010-06-11" id="1">
    <Text>The system shall...</Text>
    <trace>
        <functionalSpecId>B010134</functionalSpecId>
    </trace>
    <revisions>
        <revision date="2010-06-11" num="0">
            <description>Initial creation.</description>
        </revision>
    </revisions>
</requirement>

</requirements>

<functionalSpecs>

    <functionalSpec id="B010134" model="Model-T">
        <trace>
            <meeting></meeting>
        </trace>
        <revisions>
            <revision date="2009-07-08" num="0">
                <description>Initial creation.</description>
            </revision>
            <detailer>Me</detailer>
            <engineer>Me</engineer>
        </revisions>
    </functionalSpec>

</functionalSpecs>
</srs>

Below is the XSD file.

<?xml version="1.0" encoding="UTF-8" ?>

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

  <!-- SRS -->

  <xs:element name="srs" type="SRSType">
  </xs:element>

  <xs:complexType name="SRSType">
    <xs:sequence>
      <xs:element ref="requirements" />
      <xs:element ref="functionalSpecs" />
    </xs:sequence>
  </xs:complexType>

  <!-- Requirements -->

  <xs:element name="requirements" type="RequirementsType">
    <xs:unique name="requirementId">
      <xs:selector xpath="srs/requirements/requirement" />
      <xs:field xpath="@id" />
    </xs:unique>
  </xs:element>

  <xs:complexType name="RequirementsType">
    <xs:choice maxOccurs="unbounded">
      <xs:element name="requirement" type="RequirementType" />
    </xs:choice>
  </xs:complexType>

  <xs:complexType name="RequirementType">
    <xs:complexContent>
      <xs:extension base="RequirementInfo">
        <xs:sequence>
          <xs:element name="trace" type="TraceType" maxOccurs="unbounded" minOccurs="1" />
          <xs:element name="revisions" type="RequirementRevisions" />
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="RequirementRevisions">
    <xs:sequence>
      <xs:element name="revision" type="RevisionInfo" minOccurs="1" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="RequirementInfo">
    <xs:sequence>
      <xs:element name="Text" type="Description" />
    </xs:sequence>
    <xs:attribute name="DateCreated" type="xs:date" use="required" />
    <xs:attribute name="id" type="xs:integer" use="required" />
  </xs:complexType>

  <!-- Functional Specs -->

  <xs:element name="functionalSpecs" type="FunctionalSpecsType">
    <xs:unique name="functionalSpecId">
      <xs:selector xpath="srs/functionalSpecs/functionalSpec" />
      <xs:field xpath="@id" />
    </xs:unique>
  </xs:element>

  <xs:complexType name="FunctionalSpecsType">
    <xs:choice maxOccurs="unbounded">
      <xs:element name="functionalSpec" type="FunctionalSpecType" />
    </xs:choice>
  </xs:complexType>

  <xs:complexType name="FunctionalSpecType">
    <xs:complexContent>
      <xs:extension base="FunctionalSpecInfo">
        <xs:sequence>
          <xs:element name="trace" type="TraceType" maxOccurs="unbounded" minOccurs="1" />
          <xs:element name="revisions" type="FunctionalSpecRevisions" />
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="FunctionalSpecRevisions">
    <xs:sequence>
      <xs:element name="revision" type="RevisionInfo" minOccurs="1" maxOccurs="unbounded" />
      <xs:element name="detailer" type="xs:string" />
      <xs:element name="engineer" type="xs:string" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="FunctionalSpecInfo">
    <xs:attribute name="id" type="xs:string" use="required" />
    <xs:attribute name="model" type="xs:string" use="required" />
  </xs:complexType>

  <!-- Requirements, Functional Specs -->

  <xs:complexType name="TraceType">
    <xs:choice>
      <xs:element name="requirementId">
        <xs:keyref refer="requirementId" name="requirementIdRef">
          <xs:selector xpath="srs/requirements/requirement" />
          <xs:field xpath="@id" />
        </xs:keyref>
      </xs:element>
      <xs:element name="functionalSpecId">
        <xs:keyref refer="functionalSpecId" name="functionalSpecIdRef">
          <xs:selector xpath="srs/functionalSpecs/functionalSpec" />
          <xs:field xpath="@id" />
        </xs:keyref>
      </xs:element>
      <xs:element name="meeting" />
    </xs:choice>
  </xs:complexType>

  <!-- Common -->

  <xs:complexType name="RevisionInfo">
    <xs:choice>
      <xs:element name="description" type="Description" />
    </xs:choice>
    <xs:attribute name="date" type="xs:date" use="required" />
    <xs:attribute name="num" type="xs:integer" use="required" />
  </xs:complexType>

  <xs:complexType name="Description" mixed="true">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="Date" type="xs:date" />
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

</xs:schema>
like image 856
blastthisinferno Avatar asked Oct 25 '22 12:10

blastthisinferno


1 Answers

I'm pretty sure I have already done what you are trying to achieve here. The trick is to define the unique, key and keyref constraints at a higher level (srs element in your case). Here is some code sample which checks the "requires" elements have been defined in an item/@name :

Note how the constraints are defined at the items level.

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="item">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="special" minOccurs="0" maxOccurs="unbounded"/>
                <xs:element ref="requires" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="name" type="xs:string" use="required"/>
            <xs:attribute name="mana" type="xs:int"/>
            <xs:attribute name="life" type="xs:int"/>
            <xs:attribute name="manaRegen" type="xs:int"/>
            <xs:attribute name="hitRegen" type="xs:int"/>
            <xs:attribute name="damage" type="xs:int"/>
            <xs:attribute name="armor" type="xs:int"/>
            <xs:attribute name="attackSpeed" type="xs:int"/>
            <xs:attribute name="moveSpeed" type="xs:int"/>
            <xs:attribute name="str" type="xs:int"/>
            <xs:attribute name="agi" type="xs:int"/>
            <xs:attribute name="int" type="xs:int"/>
            <xs:attribute name="cost" type="xs:int" use="required"/>
            <xs:attribute name="image"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="items">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="shop" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="version" type="xs:string"/>
        </xs:complexType>
        <xs:unique name="uniqueItemNames">
            <xs:selector xpath="shop/item"/>
            <xs:field xpath="@name"/>
        </xs:unique>
        <xs:unique name="uniqueShopNames">
            <xs:selector xpath="shop"/>
            <xs:field xpath="@name"/>
        </xs:unique>
        <xs:key name="itemKey">
            <xs:selector xpath="shop/item"/>
            <xs:field xpath="@name"/>
        </xs:key>
        <xs:keyref name="requiresValue" refer="itemKey">
            <xs:selector xpath="shop/item/requires"/>
            <xs:field xpath="."/>
        </xs:keyref>
    </xs:element>
    <xs:element name="requires" type="xs:string"/>
    <xs:element name="shop">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="item" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="name" type="xs:string" use="required"/>
        </xs:complexType>
    </xs:element>
    <xs:simpleType name="specialType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="Activate"/>
            <xs:enumeration value="Aura"/>
            <xs:enumeration value="Effect"/>
            <xs:enumeration value="Orb"/>
            <xs:enumeration value="Info"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:element name="special">
        <xs:complexType>
            <xs:simpleContent>
                <xs:extension base="xs:string">
                    <xs:attribute name="type" type="specialType" use="required"/>
                    <xs:attribute name="mana" type="xs:int"/>
                    <xs:attribute name="cooldown" type="xs:int"/>
                    <xs:attribute name="chance" type="xs:int"/>
                </xs:extension>
            </xs:simpleContent>
        </xs:complexType>
    </xs:element>
</xs:schema>

XML Sample :

<?xml version="1.0" encoding="UTF-8"?>
<items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="dota.xsd" version="6.52d">
    <shop name="Leragas The Vile">
        <item name="Demon's Edge" image="FrostMourne.gif" cost="2600" damage="36"/>
        <item name="Eaglehorn" image="INV_Weapon_Bow_06.gif" cost="3300" agi="25"/>
        <item name="Messerschmidt's Reaver" image="SpiritWalkerMasterTraining.gif" cost="3200" str="25"/>
        <item name="Sacred Relic" image="StaffOfTeleportation.gif" cost="3800" damage="60"/>
        <item name="Hyperstone" image="Periapt1.gif" cost="2100" attackSpeed="55"/>
        <item name="Ring of Health" image="GoldRing.gif" cost="875" hitRegen="5"/>
        <item name="Void Stone" image="Periapt.gif" cost="875" manaRegen="100"/>
        <item name="Mystic Staff" image="StaffOfNegation.gif" cost="2700" int="25"/>
        <item name="Energy Booster" image="EnchantedGemstone.gif" cost="1000" mana="250"/>
        <item name="Point Booster" image="UsedSoulGem.gif" cost="1200" life="200" mana="150"/>
        <item name="Vitality Booster" image="SoulGem.gif" cost="1100" life="250"/>
    </shop>
    <shop name="Level 1 (Human) Recipes">
        <item name="Perseverance" image="OrbOfFire.gif" cost="0"  damage="10" hitRegen="5" manaRegen="125">
            <requires>Ring of Health</requires>
            <requires>Void Stone</requires>
        </item>
        <item name="Headdress of Rejuvenation" image="INV_Helmet_17.gif" cost="225" agi="2" int="2" str="2">
            <special type="Aura">+2 HP/Sec regen (500 AoE)</special>
            <requires>Ring of Regeneration</requires>
            <requires>Ironwood Branch</requires>
        </item>

    </shop>

</items>
like image 187
Michel Daviot Avatar answered Nov 10 '22 03:11

Michel Daviot