XML дизайн схемы: выбор похожих последовательностей без нарушения уникальной атрибуции частиц? - PullRequest
0 голосов
/ 06 мая 2020

Здесь новичок в схеме, я полагаю, я делаю это неправильно:

Я хотел бы создать схему .xsd, которая работает для ряда продуктов, которые могут иметь один или несколько общих элементов.

<xs:complexType>
  <xs:choice id="Media_Type" minOccurs="1" maxOccurs="1">
    <xs:sequence>
      <xs:element name="Media" fixed="12in"/>
      <xs:element name="rpm" minOccurs="1" maxOccurs="1"/>
      <xs:element name="label" minOccurs="1" maxOccurs="1"/>
      <xs:element name="tracks" type="xs:decimal" minOccurs="1" maxOccurs="1"/>
    </xs:sequence>
    <xs:sequence>
      <xs:element name="Media" fixed="7in"/>
      <xs:element name="label" minOccurs="1" maxOccurs="1"/>
      <xs:element name="playtime" type="xs:duration" minOccurs="1" maxOccurs="1"/>
    </xs:sequence>
  </xs:choice>
</xs:complexType>

... так что я могу проверить следующие две записи:

Запись A:

<Media>12in</Media>
<rpm>45</rpm>
<label>StarStruck</label>
<tracks>2</tracks>

Запись B:

<Media>7in</Media>
<label>PlatinumDunce</label>
<playtime>4:33</playtime>

Увы, "Уникальная атрибуция частиц" нарушена. В моем наивном подходе принудительный выбор между последовательностями должен точно определять атрибуцию, но я также вижу, что синтаксический анализатор может так не работать.

Как можно подойти к этому лучше? Большое спасибо!

Ответы [ 2 ]

1 голос
/ 06 мая 2020

С XSD 1.1 вы можете иметь разные модели содержимого для элемента на основе значения атрибута элемента (найдите «условное присвоение типа»). Таким образом, у вас могут быть разные модели содержимого для <Record type="LP"/> и <Record type="Single"/>. Но это может зависеть только от атрибутов самого элемента, а не, например, от атрибутов первого дочернего элемента.

1 голос
/ 06 мая 2020

Что вы можете сделать, так это сжать существующую модель содержимого в одну sequence и пометить элементы Media и label как требуемые, а остальные как необязательные.

Причина нарушения правила UPA заключается в том, что правило работает с именем элемента и игнорирует тип данных и значение элемента. Вы можете объединить два значения элемента Media ( 12 дюймов , 7 дюймов ) в один тип union и использовать его как тип элемента для <Media> (я назвал его ' TwelveOrSevenIn 'ниже). Полная схема цитируется ниже:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:simpleType name="TwelveOrSevenIn">
    <xs:restriction base="xs:string">
      <xs:enumeration value="12in" />
      <xs:enumeration value="7in" />
    </xs:restriction>
  </xs:simpleType>
  <xs:complexType name="MediaType">
    <xs:sequence>
      <xs:element name="Media" type="TwelveOrSevenIn" maxOccurs="1" minOccurs="1" />
      <xs:element name="rpm" minOccurs="0" maxOccurs="1" />
      <xs:element name="label" minOccurs="1" maxOccurs="1" />
      <xs:element name="tracks" type="xs:decimal" minOccurs="0" maxOccurs="1" />
      <xs:element name="playtime" type="xs:duration" minOccurs="0" maxOccurs="1" />
    </xs:sequence>
  </xs:complexType>
  <xs:element name="Record" type="MediaType" />
</xs:schema>

Приведенная выше схема проверяет как:

<Record>
   <Media>7in</Media>
   <label>PlatinumDunce</label>
   <!-- "4:33" is represented this way in xs:duration -->
   <playtime>PT4M33S</playtime>
</Record>

, так и

<Record>
   <Media>12in</Media>
   <rpm>45</rpm>
   <label>StarStruck</label>
   <tracks>2</tracks>
</Record>

Изменить: Итак, я оставил одну вещь Что касается правила UPA: оно также учитывает порядок элементов. Один из быстрых способов обойти правило UPA - изменить порядок конфликтующих элементов Media в одном из вложенных sequences s. Это совершенно справедливо, например:

<xs:element name="Record">
  <xs:complexType>
    <xs:choice id="Media_Type" minOccurs="1" maxOccurs="1">
      <xs:sequence>
        <xs:element name="rpm" minOccurs="1" maxOccurs="1"/>
        <xs:element name="Media" fixed="12in"/>
        <xs:element name="label" minOccurs="1" maxOccurs="1"/>
        <xs:element name="tracks" type="xs:decimal" minOccurs="1" maxOccurs="1"/>
      </xs:sequence>
      <xs:sequence>
        <xs:element name="Media" fixed="7in"/>
        <xs:element name="label" minOccurs="1" maxOccurs="1"/>
        <xs:element name="playtime" type="xs:duration" minOccurs="1" maxOccurs="1"/>
      </xs:sequence>
    </xs:choice>
  </xs:complexType>
</xs:element>

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

...