Как объявить элемент xs: с двумя разными наборами атрибутов? - PullRequest
0 голосов
/ 08 февраля 2019

Мой новый частный язык XML включает элементы <figure>, представляющие иллюстрации (изображение + подпись).

Всякий раз, когда иллюстрации ссылаются на какое-то изображение в локальной базе данных, я просто хочу набрать

<figure id="9809" width="full" />

, чтобы указать номер изображения 9809 и связанный с ним заголовок.

С другой стороны, если изображения приходят извне, мне понадобится немного другой синтаксис:

<figure href="https://some-url-here" width="full">Some ad hoc catpion</figure>

До сих пор я объявил элемент, который объединяет оба поведения, например:

  <!-- Figures -->
  <xs:simpleType name="FigureWidthEnum">
    <xs:restriction base="xs:token">
      <xs:enumeration value="center" />
      <xs:enumeration value="half" />
      <xs:enumeration value="full" />
    </xs:restriction>
  </xs:simpleType>

  <xs:element name="figure">
    <xs:complexType mixed="true">
      <xs:complexContent>
        <xs:extension base="Inline">
          <xs:attribute name="href" type="URI" />
          <xs:attribute name="id" type="xs:nonNegativeInteger" />
          <xs:attribute name="width" type="FigureWidthEnum" default="full" />
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:element>

Работает нормально, но новый редактор может связываться с 3 атрибутами и вводить невозможные вещи, которые я не хочу так просто пройти через Scheid Validator.Например:

<figure id="9809" width="full" href="https://some-unexpected-url">Some unexpected caption that should not be here</figure>

Я хочу иметь два совершенно разных синтаксиса для <figure>, как если бы я мог объявить эти два элемента с одинаковым именем:

  <xs:element name="figure">
    <xs:complexType mixed="true">
      <xs:complexContent>
        <xs:extension base="Inline">
          <xs:attribute name="href" type="URI" />
          <xs:attribute name="width" type="FigureWidthEnum" default="full" />
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
  </xs:element>

  <xs:element name="figure">
    <xs:complexType>
      <xs:attribute name="id" type="xs:nonNegativeInteger" />
      <xs:attribute name="width" type="FigureWidthEnum" default="full" />
    </xs:complexType>
  </xs:element>

На самом деле этоневозможно.

Можно ли это как-нибудь сделать?

1 Ответ

0 голосов
/ 10 февраля 2019

Да, это возможно с XSD 1.1, который предоставляет элемент <xs:alternative>, предназначенный специально для таких требований.Вот полная XML-схема, которую я разработал для проверки именно так, как вам нужно:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
           vc:minVersion="1.1">

  <!-- Figures -->
  <xs:simpleType name="FigureWidthEnum">
  <xs:restriction base="xs:token">
    <xs:enumeration value="center" />
      <xs:enumeration value="half" />
      <xs:enumeration value="full" />
    </xs:restriction>
  </xs:simpleType>

  <!-- stub definition -->
  <xs:complexType name="Inline"/>

  <!-- 'figure' element is declared once, but its type has two alternatives -->
  <xs:element name="figure">

    <!-- The first alternative is selected, when the condition specified
     in 'test' attribute is true. The condition must be a boolean XPath
     expression. The '@id' returns the value of 'id' attribute. However,
     when converted to boolean, it indicates whether 'id' attribute is
     specified at all. The anonymous complexType inside <xs:alternative>
     provides the element type valid for this case.
    -->
    <xs:alternative test="@id">
      <xs:complexType>
        <xs:attribute name="id" type="xs:nonNegativeInteger" />
        <xs:attribute name="width" type="FigureWidthEnum" default="full" />
      </xs:complexType>
    </xs:alternative>

    <!-- The second alternative has no 'test' attribute. That means, it must
     be selected by default, when all other alternatives (with a specified
     test condition) do not pass. Here, the anonymous complexType inside
     <xs:alternative> defines the element type in case of reference:
     when 'href' is present.
    -->
    <xs:alternative>
      <xs:complexType mixed="true">
        <xs:complexContent>
          <xs:extension base="Inline">
            <xs:attribute name="href" type="xs:anyURI" />
            <xs:attribute name="width" type="FigureWidthEnum" default="full" />
          </xs:extension>
        </xs:complexContent>
      </xs:complexType>
    </xs:alternative>
  </xs:element>

  <!-- this element is defined just to test the whole schema in XML below -->
  <xs:element name="figures">
    <xs:complexType>
      <xs:sequence>    
        <xs:element ref="figure" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>    
    </xs:complexType>
  </xs:element>

</xs:schema>

Полный XML-файл, проверяемый этой схемой:

<?xml version="1.0" encoding="UTF-8"?>
<figures>

  <!-- passes validation -->
  <figure id="9809" width="full" />

  <!-- passes validation -->
  <figure width="full" href="https://some-unexpected-url">Some ad hoc caption</figure>

  <!-- does not pass the validation -->
  <figure id="9809" width="full" href="https://some-unexpected-url">
    Some unexpected caption that should not be here
  </figure>

</figures>

Проверка была выполнена с помощью Apache Xerces 2.11.0 (XSD 1.1 в курсе).


Промо-дополнение.Эти ссылки могут быть интересны тем, кто работает со схемами XML и WSDL: FlexDoc / XML XSDDoc & WSDLDoc - Высокопроизводительные универсальные генераторы документации XML-схем / WSDL сДиаграммы

...