Xsd key / keyref: structure hiérarchique des clés

j'essaie de définir quelques contraintes de clé étrangère sur un schéma XML en utilisant les définitions de xs:key et XS:keyref. Je veux la structure du document structure hiérarchique de la façon suivante:

<?xml version="1.0" encoding="UTF-8"?>
<tns:root xmlns:tns="http://www.example.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/ SampleSchema.xsd ">
  <parent parentKey="parent1">
    <child childKey="child1"/>
    <child childKey="child2"/>
  </parent>
  <parent parentKey="parent2">
    <child childKey="child1"/>
    <child childKey="child2"/>
  </parent>
  <referrer parentRef="parent1" childRef="child2"/>
</tns:root>

a chaque parent a une clé (globale) unique, définie par parent-key. Chaque enfant a une clé définie par childKey,mais childKey est seulement unique dans le cadre de son contenant parent.

il y a alors une liste de référents avec des références à une clé étrangère un parent et un enfant en particulier.

je suis capable de définir les clés comme je veux, simplement en les mettant sur l'élément correct: la contrainte parentKey sur l'élément racine, et la contrainte childKey sur l'élément parent. Je peux aussi définir le keyref de parentKey sans difficulté.

les problèmes surgissent en essayant de définir un keyref à childKey. J'ai essayé de définir un simple keyref sur l'élément root à childKey, mais cela ne fonctionne pas car je ne vois aucun moyen de sélectionner seulement le éléments d'enfant sous le bon subtree parent. (Le validateur Eclipse, au moins, valide toujours simplement par rapport au contenu du dernière parent subtree dans le document...).

j'ai alors essayé de définir une clé composite( sur root), avec:

  • sélecteur = parent
  • champ = @parentKey
  • champ = enfant/@childKey

ceci échoue s'il y a plus d'un enfant défini sous le parent. C'est l' comportement correct basé sur le XSD 1.1 spec, section 3.11.4, article 3, qui stipule que la clé doit correspondre à au plus un nœud par définition d'un champ.

pour rappel: si je force childKeys à être globalement unique, c'est facile à mettre en œuvre; la difficulté est autour du référencement en local unique childKeys.

N'importe quels maîtres XSD là-bas ont une idée?

pour référence, voici un exemple de XSD, avec une clé childKey en panne commenté:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/" xmlns:tns="http://www.example.org/" elementFormDefault="unqualified">

    <element name="root">
        <complexType>
            <sequence>
                <element name="parent" maxOccurs="unbounded" minOccurs="1">
                    <complexType>
                        <sequence>
                            <element name="child" maxOccurs="unbounded" minOccurs="1">
                                <complexType>
                                    <attribute name="childKey" type="string" use="required"/>
                                </complexType>
                            </element>
                        </sequence>
                        <attribute name="parentKey" type="string" use="required"/>
                    </complexType>
                    <key name="childKeyDef">
                        <selector xpath="child"/>
                        <field xpath="@childKey"/>
                    </key>
                </element>
                <element name="referrer" maxOccurs="unbounded" minOccurs="1">
                    <complexType>
                        <attribute name="parentRef" type="string"/>
                        <attribute name="childRef" type="string"/>
                    </complexType>
                </element>
            </sequence>
        </complexType>
        <key name="parentKeyDef">
            <selector xpath="parent"/>
            <field xpath="@parentKey"/>
        </key>
        <keyref name="parentKeyRef" refer="tns:parentKeyDef">
            <selector xpath="referrers"/>
            <field xpath="@parentRef"/>
        </keyref>
<!--        <keyref name="childKeyRef" refer="tns:childKeyDef">-->
<!--            <selector xpath="referrers"/>-->
<!--            <field xpath="@childRef"/>-->
<!--        </keyref>-->
    </element>
</schema>
13
demandé sur Aron 2009-05-21 07:45:15

3 réponses

Que Diriez-vous de faire référence au parent de l'enfant? Même s'il y a beaucoup d'enfants, il n'y aura qu'un seul parent, et la combinaison du (parent,enfant) crée une clé unique à l'échelle mondiale, même si la clé enfant n'est unique qu'à l'intérieur de son parent:

  <key name="childKeyDef">
    <selector xpath="child"/>
    <field xpath="@childKey"/>
    <field xpath="../@parentKey"/>
  </key>

cela ne fonctionne pas dans xmllint, même si le spec ne semble pas explicitement refuser cela pour les champs-seulement pour les sélecteurs: 3.11.4, (2) dit le sélecteur ne peut pas être un ancêtre, il ne peut être le nœud de contexte ou descendants.)

Ah, voici le clou dans le cercueil (en regardant la syntaxe spécifique): les expressions XPath autorisées sont très limitées, et ne comprennent tout simplement pas ".."http://www.w3.org/TR/xmlschema-1/#c-fields-xpaths

Donc, désolé, ce n'est pas la réponse à votre question, mais peut-être que ça vous donnera quelques idées.

2
répondu 13ren 2009-05-21 13:47:36

une solution moche est de changer votre format XML, de sorte que la clé parent soit incluse dans chaque enfant, comme ceci:

<parent>
  <child parentKey="parent1" childKey="child1"/>
  <child parentKey="parent1" childKey="child2"/>
</parent>

je pense que votre situation est très légitime, et je m'attends à ce qu'il y ait un moyen de le faire - pourquoi ne pas essayer la liste de diffusion xml-dev? Il est devenu bruyant dernière, j'ai vérifié, mais certains des créateurs de xml étaient toujours en suspens.

1
répondu 13ren 2009-05-22 08:38:12

j'avais une question similaire: touche de schéma XML avec plusieurs champs

j'ai décidé que la meilleure approche pour moi était de réorganiser le XML pour permettre que la portée soit déterminée par localité au lieu d'appliquer une clé avec deux champs.

dans votre scénario, si vous déplacez le referrer à l'intérieur du parent, cela permettra de définir la portée pour référencer l'enfant approprié. Vous obtiendriez alors que l'élément referrer se réfère à la portée externe de l'élément qui il doit faire référence.

C'est un peu dur à déterminer si c'est une solution acceptable, car votre problème semble être un peu abstraite. Dans mon problème, décrit dans ma question, je m'occupais des questions, des réponses et des réponses des utilisateurs. À l'origine, j'essayais de valider si la réponse d'un utilisateur était en fait une réponse valide; ma première approche comportait la même technique que celle que vous utilisez. Ma solution finale a consisté à déplacer la réponse à l'intérieur de la question, et puis se référant à l'utilisateur.

mon XML avant:

<?xml version="1.0" encoding="utf-8"?>
<survey>
  <user id="bob">
    <response questionIdRef="q101">yes</response>
    <response questionIdRef="q102">white</response>
  </user>
  <user id="jane">
    <response questionIdRef="q101">no</response>
    <response questionIdRef="q102">blue</response>
  </user>
  <question id="q101">
    <text>Do you like the color red?</text>
    <answer>yes</answer>
    <answer>no</answer>
  </question>
  <question id="q102">
    <text>What is your favorite color?</text>
    <answer>red</answer>
    <answer>blue</answer>
    <answer>white</answer>
    <answer>yellow</answer>
  </question>
</survey>

mon XML après:

<?xml version="1.0" encoding="utf-8"?>
<survey>
  <user id="bob" />
  <user id="jane" />
  <question id="q101">
    <text>Do you like the color red?</text>
    <answer>yes</answer>
    <answer>no</answer>
    <response userIdRef="bob">yes</response>
    <response userIdRef="jane">no</response>
  </question>
  <question id="q102">
    <text>What is your favorite color?</text>
    <answer>red</answer>
    <answer>blue</answer>
    <answer>white</answer>
    <answer>yellow</answer>
    <response userIdRef="bob">white</response>
    <response userIdRef="jane">blue</response>
  </question>
</survey>
0
répondu Chris 2017-05-23 12:00:17