Как сделать взаимоисключающие атрибуты в XML-схеме? - PullRequest
14 голосов
/ 22 декабря 2008

Я пытаюсь сделать два атрибута XML взаимоисключающими. Как можно создать схему XSD для захвата такого сценария?

Я хотел бы иметь один из этих

<elem value="1" />
<elem ref="something else" />

но не

<elem value="1" ref="something else" />

Ответы [ 6 ]

9 голосов
/ 22 декабря 2008

Вы не можете делать с атрибутами, но вы можете делать с дочерними элементами ...

<element name="elem">
    <complexType>
        <choice>
            <element name="value"/>
            <element name="ref"/>
        </choice>
    </complexType>
</element>

Таким образом, вы можете иметь ...

<elem>
    <value>1</value>
</elem>

или ...

<elem>
    <rel>something else</rel>
</elem>
7 голосов
/ 22 декабря 2008

К сожалению, AFAIK, вы не можете сделать это с XML-схемой, у меня была такая же проблема.

Я видел, что если вам нужны оба:

<elem type="xxx"> 
<elem ref="yyy">

затем <elem> само должно быть разделено на два типа, поскольку они явно имеют разные атрибуты ...

5 голосов
/ 23 декабря 2008

Поскольку RelaxNG было упомянуто в ответе Альнитака, вот решение с RelaxNG (язык, который в большинстве случаев лучше, чем W3C Схема). Запишите ИЛИ (|) в определении elem:

start = document
document = element document {elem+}
elem = element elem {ref | value}
ref = attribute ref {text}
value = attribute value {xsd:integer}

Если у меня есть этот XML-файл:

<document>
    <elem value="1" />
    <elem ref="something else" />
</document>

Принят рН и xmlint :

 % rnv attributes-exclusive.rnc attributes-exclusive.xml             
 attributes-exclusive.xml

 % xmllint --noout --relaxng attributes-exclusive.rng attributes-exclusive.xml 
 attributes-exclusive.xml validates

Если я добавлю в файл XML:

<elem value="1" ref="something else" />

Я получаю ошибки проверки, как я хочу (обратите внимание, что сообщения об ошибках являются субоптимальными):

% rnv attributes-exclusive.rnc attributes-exclusive.xml    
attributes-exclusive.xml
attributes-exclusive.xml:4:0: error: attribute ^ref not allowed
required:
       after

% xmllint --noout --relaxng attributes-exclusive.rng attributes-exclusive.xml
attributes-exclusive.xml:4: element elem: Relax-NG validity error : Invalid attribute value for element elem
attributes-exclusive.xml fails to validate
2 голосов
/ 08 ноября 2017

На самом деле, можно определить в XSD 1.0, используя ограничения идентичности через xs: unique или xs: key. Какой из них выбрать, зависит от того, как будут обрабатываться элементы без любого из двух атрибутов: они действительны с xs: уникальным, но недействительны с xs: key. Пример кода ниже содержит оба варианта; обязательно удалите один из них, в противном случае «более строгий» ключ xs: имеет приоритет над xs: уникальным, т. е. требуется один из двух атрибутов.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified" attributeFormDefault="unqualified">
  <xs:element name="container">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="elem" maxOccurs="unbounded">
          <xs:complexType>
            <xs:attribute name="value" use="optional"/>
            <xs:attribute name="ref" use="optional"/>
          </xs:complexType>
          <!-- Note: Use either xs:unique or xs:key -->
          <xs:unique name="attrsExclusiveOptional">
            <xs:annotation>
              <xs:documentation>Ensure that @value and @ref cannot occur simultaneously.
Both may be omitted.</xs:documentation>
            </xs:annotation>
            <xs:selector xpath="."/>
            <xs:field xpath="@value | @ref"/>
          </xs:unique>
          <xs:key name="attrsExclusiveRequired">
            <xs:annotation>
              <xs:documentation>Ensure that @value and @ref cannot occur simultaneously.
One of them is required.</xs:documentation>
            </xs:annotation>
            <xs:selector xpath="."/>
            <xs:field xpath="@value | @ref"/>
          </xs:key>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Это подтверждает следующий XML-файл:

<?xml version="1.0" encoding="UTF-8"?>
<container xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:noNamespaceSchemaLocation="schema.xsd">
  <!-- Shall pass: -->
  <elem value="1" />
  <elem ref="something else" />

  <!-- Passes for xs:unique, fails for xs:key: -->
  <elem />

  <!-- Shall fail: -->
  <elem value="1" ref="something else" />
</container>
2 голосов
/ 26 января 2013

XSD имеет абстрактные типы для этого: http://www.tek -tips.com / viewthread.cfm? Qid = 1364846 (см. Сообщение от tsuji)

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

Затем вы создаете 2 (или более) дополнительных сложных типов, которые расширяют абстрактный тип, который я только что упомянул. В этих новых типах вы определяете различные наборы атрибутов для каждого варианта использования. Вот и все для XSD-части.

Наконец, вам нужно добавить атрибут XSI type к результирующему элементу в документе экземпляра схемы. Таким образом, чтобы быть действительным, элемент теперь должен иметь либо один набор атрибутов, либо другой.

Не прямолинейно, но гибко, и, как мы все знаем: чем гибче, тем труднее становится что-то.

1 голос
/ 30 декабря 2014

Для читателей, приходящих к этому позже, обратите внимание, что проблему можно решить в XSD 1.1, используя либо «условное присвоение типа», либо утверждения.

...