XML Schema Unique/key constraint

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 12-09 11:48
Ik ben me nu al een langere tijd aan het verdiepen in de wondere wereld van XML en ik moet zeggen dat het me steeds beter begint te bevallen. Vooral de mogelijkheden van XML Schema zijn fantastisch. Echter valt de hoeveelheid informatie en voorbeelden op het net me tegen. Ik heb daarom ook een boek gekocht 'XML Schema' door Eric van der Vlist.

Nu wil ik unique constraints en keys toepassen op diverse attributen.

Ik stel mijn hoofddocument samen uit diverse subschema definities. Dit werkt prima.

DatabaseTypes.xsd
XML:
1
2
3
4
5
6
7
8
9
    <xs:complexType name="groupType">
        <xs:sequence>
            <xs:element name="name" type="xs:NMTOKEN" />
            <xs:element name="description" type="xs:string"
                minOccurs="0" />
        </xs:sequence>

        <xs:attribute name="id" type="xs:NCName"/>
    </xs:complexType>


Database.xsd
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
        targetNamespace="http://www.example.org/Database.xsd"
        xmlns:dbt="http://www.example.org/DatabaseTypes"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        elementFormDefault="qualified">
    <xs:import namespace="http://www.example.org/DatabaseTypes" schemaLocation="DatabaseTypes.xsd"/>
    
    <xs:element name="database">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="groups">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="group" type="dbt:groupType" minOccurs="0" maxOccurs="unbounded"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>


Ik wil nu twee dingen doen. Ik wil door het hele document het attribuut 'id' uniek verklaren. Dit zou ik willen doen dmv een unique element:

XML:
1
2
3
4
        <xs:unique name="ID">
            <xs:selector xpath=".//group|.//user|.//table"/>
            <xs:field xpath="@id"/>
        </xs:unique>


Echter valideert mijn document nog steeds, ook al staan er meerdere group-elementen met hetzelfde id.

Tevens wil ik de group-name als key kunnen gebruiken. Dit probeer ik met:
XML:
1
2
3
4
        <xs:key name="GroupName">
            <xs:selector xpath=".//group"/>
            <xs:field xpath="name"/>
        </xs:key>


Ook dit valideert als ik meerdere group-elementen heb met dezelfde naam. Het is natuurlijk nog mooier deze definitie te verplaatsen binnen de 'groups' definitie, echter lost dit ook niets op.

Ik denk zelf dat dit aan het gebruik van namespaces ligt, maar ik kan de oplossing niet vinden.

Zou ik bijvoorbeeld een selector als deze moeten gebruiken:
XML:
1
2
3
4
        <xs:key name="GroupName">
            <xs:selector xpath=".//dbt:group"/>
            <xs:field xpath="name"/>
        </xs:key>


Het group-element komt namelijk uit de db-namespace en het name-element daarbinnen uit de dbt-namespace.

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • SanderI
  • Registratie: Januari 2007
  • Laatst online: 11-09 16:12
Het makkelijkste is het xs:unique gebruiken alleen je moet wel met namespaces werken binnen de unique anders gaat het niet werken.

Snel voorbeeld:

XSD:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/XMLSchema.xsd"
    xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <xs:element name="top" type="mstns:entityType">
    <xs:unique name="test">
      <xs:selector xpath="mstns:entity" />
      <xs:field xpath="@id" />
    </xs:unique>
  </xs:element>

  <xs:complexType name="entityType">
    <xs:sequence minOccurs="1" maxOccurs="unbounded">
      <xs:element name="entity">
        <xs:complexType>
          <xs:attribute type="xs:integer" name="id" />
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:schema>


Sample XML:
XML:
1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<top xmlns="http://tempuri.org/XMLSchema.xsd">
  <entity id="1" />
  <entity id="2" />
  <entity id="2" />
  <entity id="1" />
</top>


Zo krijg ik een fout "duplicate key sequence" of iets dergelijks.

Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 12-09 11:48
Thnx Sander. Ik had zelf ook nog niet opgegeven en kwam op iets soortgelijks uit, onderstaande bewijst hetzelfde, maar is iets complexer. Wellicht dat in de toekomst iemand hier nog iets aan heeft:

Voor de duidelijkheid, let vooral op de onderste vier groepen, deze definiëren constraints binnen de XML.

XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
        targetNamespace="http://www.example.org/Database.xsd"
        xmlns:com="http://www.example.org/CommonTypes"
        xmlns:dbt="http://www.example.org/DatabaseTypes"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        elementFormDefault="qualified" 
        xmlns:db="http://www.example.org/Database.xsd">
        
    <xs:import namespace="http://www.example.org/CommonTypes" schemaLocation="CommonTypes.xsd"/>
    <xs:import namespace="http://www.example.org/DatabaseTypes" schemaLocation="DatabaseTypes.xsd"/>
    
    <xs:element name="database">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="rdbms" type="dbt:rdbmsType"/>
                
                <xs:element name="groups">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="group" type="dbt:groupType" minOccurs="0" maxOccurs="unbounded"/>
                        </xs:sequence>
                    </xs:complexType>
                    
                </xs:element>
                
                <xs:element name="users">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="user" type="dbt:userType" minOccurs="0" maxOccurs="unbounded"/>
                        </xs:sequence>
                    </xs:complexType>
                    
                </xs:element>   
            </xs:sequence>
            <xs:attribute name="sequence" type="xs:int" use="required"/>
        </xs:complexType>
        
        <xs:unique name="ID">
            <xs:selector xpath=".//db:group|.//db:user|.//db:table|.//db:column|.//db:constraint"/>
            <xs:field xpath="@id"/>
        </xs:unique>
                
        <xs:key name="UserName">
            <xs:selector xpath=".//db:user"/>
            <xs:field xpath="dbt:name"/>
        </xs:key>
        
        <xs:key name="GroupName">
            <xs:selector xpath=".//db:group"/>
            <xs:field xpath="dbt:name"/>
        </xs:key>
        
        <xs:keyref name="GroupMemberGroup" refer="db:GroupName">
            <xs:selector xpath=".//db:group/dbt:members"/>
            <xs:field xpath="dbt:group"/>
        </xs:keyref>
        
        <xs:keyref name="GroupMemberUser" refer="db:UserName">
            <xs:selector xpath=".//db:group/dbt:members"/>
            <xs:field xpath="dbt:user"/>
        </xs:keyref>
    </xs:element>
</xs:schema>

"Chaos kan niet uit de hand lopen"