2009-05-21 8 views
13

Próbuję zdefiniować niektóre ograniczenia klucza obcego w schemacie XML za pomocą definicji xs: key i xs: keyref. Chcę struktura dokumentu być hierarchiczna w następujący sposób:Klucz/klucz XSD: hierarchiczna struktura klucza

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

każdy rodzic ma (globalnie) unikatowy klucz, zdefiniowane przez parentKey. Każde dziecko ma klucz zdefiniowany przez childKey, , ale childKey jest tylko unikalny w zakresie swojego rodzica zawierającego.

Istnieje lista polecających z kluczami obcymi do konkretnego rodzica i dziecka.

Jestem w stanie zdefiniować klucze, jak chcę, po prostu umieszczając je na właściwym elemencie: ograniczenie parentKey na element główny i ograniczenie childKey na elemencie nadrzędnym. Mogę również bezbłędnie zdefiniować keyref do parentKey.

Problemy pojawiają się podczas próby zdefiniowania elementu keyref na childKey. Próbowałem zdefiniować prosty keyref na głównym elemencie do childKey, ale to nie działa, ponieważ nie widzę sposobu, aby wybrać tylko elementy podrzędne w odpowiednim nadrzędnym poddrzewie. (Przynajmniej weryfikator Eclipse zawsze po prostu sprawdza poprawność w stosunku do zawartości poddrzewa nadrzędnego w dokumencie ...).

Następnie próbowałem definiowania klucza kompozytowego (na root), z:

  • selektor = nadrzędnej
  • pole = @parentKey
  • pole = dziecko/@ childKey

ten kończy się niepowodzeniem, jeśli zdefiniowano więcej niż jedno dziecko pod rodzicem. Jest to poprawne zachowanie oparte na XSD 1.1 spec, sekcja 3.11.4, pozycja 3, która stwierdza, że ​​klucz musi pasować co najwyżej do jednego węzła na definicję pola.

Tylko powtórzyć: jeśli zmusić ChildKeys do globalnej unikalności, jest to łatwe do wdrożenia; trudność polega na odwoływaniu się do lokalnie unikalnych childKeys.

Każdy mistrz XSD ma pomysł?

Dla porównania, oto próbka XSD, z nieudanej childKey keyref wykomentowane:

<?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, znaleźliście rozwiązanie tego problemu? Utknąłem z podobnym problemem (nie mogę zmienić mojego xml). – Rahul

+1

Obawiam się, że nie - skończyło się przejściem do formatu XML na wymianę danych, co spowodowało dyskusję. – Aron

Odpowiedz

2

Jak o odnosząc się do rodzica od dziecka? Nawet jeśli wielu dzieci, nie będzie tylko jeden rodzic, a łączenie (rodzic, dziecko) tworzy globalnie unikatowy klucz, choć kluczem dziecko jest wyjątkowe tylko w jego rodzica:

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

To nie działa w xmllint, nawet jeśli specyfikacja nie wydaje się jawnie tego nie akceptować dla pól - tylko dla selektorów: 3.11.4, (2) mówi, że selektor nie może być przodkiem (może to być tylko węzeł kontekstu lub potomkowie).

Ach, oto gwóźdź do trumny (patrząc na określoną składnię): dozwolone wyrażenia XPath są bardzo ograniczone i po prostu nie zawierają ".."http://www.w3.org/TR/xmlschema-1/#c-fields-xpaths

Więc, przepraszam, to nie odpowiedzieć na to pytanie, ale może to daje kilka pomysłów.

+1

Tak; Próbowałem tego samego i dokonałem tego samego odkrycia na temat ścisłych ograniczeń wyrażeń selektora i pola xpath. Niezły pomysł w teorii. Dzięki za wysiłek! – Aron

+0

Przypuszczam, że przy łączeniu tego ograniczenia, wraz z innym ograniczeniem, które znalazłeś (aby xpath odnosił się tylko do jednego węzła), istnieje dowód, że to, co chcesz zrobić, jest niemożliwe w XSD - Założę się, że dowód (jeśli istnieje jest jeden) jest bardzo prosty, ale nie mogę go zobaczyć. – 13ren

1

Jest brzydki rozwiązaniem jest zmienić format XML, dzięki czemu parentKey jest zawarty w każdym dzieckiem w następujący sposób:?

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

Myślę, że sytuacja jest bardzo uzasadnione, a ja się spodziewać tam być jakiś sposób, aby to zrobić - dlaczego nie spróbować listę xml-dev mailingowej Stało się głośny ostatnio sprawdziłem, ale niektórzy twórcy xml wciąż tam byli.

+0

Tak, to byłaby możliwość, ale myślę, że powoduje więcej problemów niż rozwiązuje ... jak mówisz, brzydko. Mój projekt został przeniesiony z tej struktury z przyczyn zewnętrznych, więc jest to bardziej akademickie ćwiczenie w tym miejscu, ale może dam mu spróbować. Dzięki za pomysł! – Aron

0

Miałem podobne pytanie: XML Schema Key with multiple fields

Postanowiłem, że najlepszym sposobem jest dla mnie zmiana kolejności kodu XML, aby umożliwić ustalenie zasięgu według lokalizacji, zamiast egzekwowania klucza z dwoma polami.

W twoim scenariuszu, jeśli przeniesiesz stronę odsyłającą do jednostki nadrzędnej, pozwoli to na ustawienie zakresu w celu odniesienia do odpowiedniego dziecka. Wówczas element referrer odwoływałby się do zewnętrznego zakresu do elementu, który musi się odwoływać.

To jest trochę trudne do określenia, czy jest to dopuszczalne rozwiązanie, ponieważ problem wydaje się być trochę abstrakcyjny. W moim problemie, opisanym w moim pytaniu, miałem do czynienia z pytaniami, odpowiedziami i odpowiedziami użytkowników. Pierwotnie próbowałem sprawdzić, czy odpowiedź użytkownika była rzeczywiście poprawną odpowiedzią; moje pierwsze podejście dotyczyło tej samej techniki, której używasz. Moje ostateczne rozwiązanie polegało na przeniesieniu odpowiedzi do pytania, a następnie nawiązaniu do użytkownika.

Moje XML PRZED:

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

Moje XML PO:

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