2009-05-21 4 views
13

Я пытаюсь определить некоторые ограничения внешнего ключа для схемы XML, используя определения xs: key и xs: keyref. Я хочу, чтобы структура документа быть иерархической следующим образом:XSD key/keyref: иерархическая ключевая структура

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

каждый родитель имеет (глобально) уникальный ключ, определенный parentKey. Каждый ребенок имеет ключ, определяемый childKey, , но childKey уникален только в пределах его содержащего родителя.

Существует список ссылок с ссылками на внешние ключи к определенному родительскому и дочернему объектам.

Я могу определить ключи, как я хочу, просто поставив их на правильный элемент: ограничение parentKey на корневой элемент и ограничение childKey на родительский элемент. Я также могу определить keyref для parentKey без труда.

Проблемы возникают при попытке определить keyref для childKey. Я попытался определить простой keyref в корневом элементе childKey, но это не работает, поскольку я не вижу способа выбрать только дочерние элементы под соответствующим родительским поддеревом. (Валидатор Eclipse, по крайней мере, всегда просто проверяет содержимое последнего родительского поддерева в документе ...).

Затем я попытался определения составной ключ (на корень), с:

  • селектором = родительском
  • поля = @parentKey
  • поле = ребенок/@ childKey

Этот если существует более одного дочернего элемента, определенного под родителем. Это правильное поведение, основанное на разделе 3.11.4, пункт 3 XSD 1.1 spec, в котором говорится, что ключ должен соответствовать не более одного узла для определения поля.

Просто повторю: если я вынужу childKeys быть глобально уникальными, это легко реализовать; трудность вокруг ссылки локально уникальный childKeys.

У всех мастеров XSD есть идея?

Для справки, вот пример XSD, с отказавшим childKey KeyRef закомментирована:

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

Привет Арон ли вы найти решение этой проблемы? Я также придерживаюсь аналогичной проблемы (я не могу изменить свой xml). – Rahul

+1

Я боюсь, что нет - мы перешли к не-XML-формату обмена данными, поставив вопрос спорным. – Aron

ответ

2

Как насчет ссылаясь на родителей от ребенка? Даже если много детей, там будет только один из родителей, и объединение (родитель, ребенок) создает глобально уникальный ключ, даже если ключ ребенок уникален только в пределах его родителя:

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

Это не работает в xmllint, хотя спецификация явно не запрещает это для полей - только для селекторов: 3.11.4, (2) говорит, что селектор не может быть предком (это может быть только контекстный узел или потомки.)

А вот вот гвоздь в гробу (смотря на конкретный синтаксис): разрешенные выражения XPath очень ограничены и просто не включают «.."http://www.w3.org/TR/xmlschema-1/#c-fields-xpaths

Так, извините, это не ответ на ваш вопрос, но, возможно, это даст вам некоторые идеи.

+1

Да; Я сам это пробовал и сделал одно и то же открытие о строгих ограничениях на выражения селектора и поля xpath. Хорошая идея в теории. Спасибо за усилия! – Aron

+0

Я предполагаю, что при объединении этого ограничения вместе с другим найденным ограничением (для того, чтобы xpath ссылался только на один узел), есть доказательство того, что то, что вы хотите сделать, невозможно в XSD - я ставлю доказательство (если там это одно) очень просто, но я не могу это увидеть. – 13ren

1

Уродливые решение изменить формат XML, так что parentKey входит в состав каждого ребенка , как это:

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

Я думаю, что ваша ситуация очень законны, и я ожидаю, что должен быть способ сделать это - почему бы не попробовать список XML-DEV рассылки это стало шумно в прошлом я проверил, но некоторые из создателей xml все еще висят там.

+0

Да, это было бы возможно, но я думаю, что это вызывает больше проблем, чем решает ... как вы говорите, уродливо. Мой дизайн отошел от этой структуры по внешним причинам, поэтому на данный момент это скорее академическое упражнение, но, возможно, я дам список попробовать. Спасибо за идею! – Aron

0

У меня был аналогичный вопрос: XML Schema Key with multiple fields

Я решил, что лучший подход для меня состоял в том, чтобы переупорядочить XML, чтобы разрешить определение области по локальности вместо принудительного применения ключа с двумя полями.

В вашем случае, если вы переместите реферер внутри родителя, это позволит установить область для ссылки на соответствующий дочерний элемент. Затем вы должны были бы ссылаться на внешний объект на элемент, который он должен ссылаться.

Немного сложно определить, является ли это приемлемым решением, потому что ваша проблема выглядит немного абстрагированной. В моей проблеме, описанной в моем вопросе, я имел дело с вопросами, ответами и ответами пользователей. Сначала я пытался проверить, действительно ли ответ пользователя был действительным ответом; мой первый подход включал ту же технику, которую вы используете. Моим окончательным решением было перемещение ответа внутри вопроса, а затем обращение к пользователю.

Мой XML ДО:

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

Мой XML ПОСЛЕ:

<?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> 
Смежные вопросы