2009-05-21 17 views
13

Sto provando a definire alcuni vincoli di chiave esterna su uno schema XML utilizzando xs: key e xs: definizioni keyref. Voglio la struttura del documento di essere gerarchico nel seguente modo:XSD key/keyref: struttura chiave gerarchica

<?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 ciascun genitore ha una chiave univoca (a livello mondiale), definito da parentKey. Ogni bambino ha una chiave definita da childKey, ma childKey è solo univoco nell'ambito di parentela contenente.

Esiste quindi un elenco di referenti con riferimenti a chiave esterna a un particolare genitore e figlio.

Sono in grado di definire i tasti come voglio, semplicemente inserendoli sull'elemento corretto: il vincolo parentKey sull'elemento radice e il vincolo childKey sull'elemento padre. Posso anche definire il keyref di parentKey senza difficoltà.

I problemi sorgono quando si tenta di definire un keyref per childKey. Ho provato a definire un keyref semplice sull'elemento root su childKey, ma ciò non funziona poiché non vedo alcun modo per selezionare solo gli elementi figlio sotto il sottoalbero genitore appropriato. (Il validatore di Eclipse, almeno, convalida sempre semplicemente il contenuto dello albero secondario genitore nel documento ...).

poi ho provato definente una chiave composta (su root), con:

  • selettore = genitore
  • campo = @parentKey
  • campo = bambino/@ ChildKey

Questo fallisce se c'è più di un figlio definito sotto il genitore. Questo è il comportamento corretto basato su XSD 1.1 spec, sezione 3.11.4, elemento 3, in cui si afferma che la chiave deve corrispondere al massimo a un nodo per ogni definizione di campo.

Giusto per ribadire: se impongo che childKeys sia globalmente unico, è facile da implementare; la difficoltà è intorno al riferimento localmente childKeys unici.

Qualsiasi maestro XSD là fuori ha un'idea?

Per riferimento, ecco un XSD di esempio, con una non riuscita ChildKey keyref commentato out:

<?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> 
+1

Hi Aron, hai trovato una soluzione per questo problema? Sono anche bloccato con un problema simile. (Non posso cambiare il mio xml). – Rahul

+1

Ho paura di no - abbiamo finito per passare a un formato non XML per lo scambio di dati, rendendo la domanda discutibile. – Aron

risposta

2

Come circa riferendosi al genitore del bambino? Anche se molti bambini, non ci sarà un solo genitore, e combinando la (genitore, figlio) crea una chiave univoca a livello globale, anche se la chiave di bambino è unico solo all'interno del suo genitore:

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

Questo non funziona in xmllint, anche se le specifiche non sembrano rifiutare esplicitamente questo per i campi - solo per i selettori: 3.11.4, (2) il selettore non può essere un antenato (può essere solo il nodo di contesto o discendenti).

Ah, ecco il chiodo nella bara (guardando la sintassi specifica): le espressioni XPath consentite sono molto limitate e semplicemente non includono ".."http://www.w3.org/TR/xmlschema-1/#c-fields-xpaths

Quindi, mi dispiace, questo non risponde alla tua domanda, ma forse vi darà alcune idee.

+1

Sì; L'ho provato io stesso e ho fatto la stessa scoperta riguardo alle rigorose limitazioni sul selettore e sulle espressioni xpath di campo. Bella idea in teoria, però. Grazie per gli sforzi! – Aron

+0

Io congettura che, combinando questo vincolo, insieme con l'altro vincolo trovato (per un xpath si riferisca a un solo nodo), c'è una prova che ciò che si vuole fare è impossibile in XSD - scommetto la dimostrazione (se c'è è uno) è molto semplice, ma non riesco a vederlo. – 13ren

1

Una soluzione brutto è quello di cambiare il formato XML, in modo che il parentKey è incluso in ogni bambino , in questo modo:?

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

Penso che la tua situazione è molto legittima, e mi aspetto che ci sia un modo per farlo - perché non provare il xml-dev mailing list e 'diventato rumoroso ultima volta che ho controllato, ma alcuni dei creatori di xml erano ancora appesi là.

+0

Sì, sarebbe una possibilità, ma penso che causi più problemi di quanti ne risolva ... come dici tu, brutto. Il mio design si è allontanato da questa struttura per motivi esterni, quindi è più un esercizio accademico a questo punto, ma forse darò una prova alla lista. Grazie per l'idea! – Aron

0

Ho avuto una domanda simile: XML Schema Key with multiple fields

Ho deciso che l'approccio migliore per me era quello di riordinare l'XML per consentire che lo scope fosse determinato dalla località invece di imporre una chiave con due campi.

Nello scenario, se si sposta il referrer all'interno del padre, questo consentirà di impostare l'ambito per fare riferimento al figlio appropriato. Dovresti quindi fare riferimento all'elemento referrer all'ambito esterno dell'elemento a cui ha bisogno di fare riferimento.

È un po 'difficile determinare se questa è una soluzione accettabile perché il problema sembra essere un po' astratto. Nel mio problema, descritto nella mia domanda, avevo a che fare con domande, risposte e risposte dell'utente. Inizialmente, stavo cercando di convalidare se la risposta di un utente era in realtà una risposta valida; il mio primo approccio riguardava una stessa tecnica che stai usando. La mia soluzione finale consisteva nel spostare la risposta all'interno della domanda e poi nel riferirsi all'utente.

mio XML prima:

<?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> 

mio XML DOPO:

<?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> 
Problemi correlati