XML и XSD — используйте имя элемента вместо xsi:type для полиморфизма

В качестве примера возьмем XSD автомобиля W3C:

<schema xmlns="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://cars.example.com/schema"
           xmlns:target="http://cars.example.com/schema">

  <complexType name="Vehicle" abstract="true"/>

  <complexType name="Car">
    <complexContent>
      <extension base="target:Vehicle"/>
      ...
    </complexContent>
  </complexType>

  <complexType name="Plane">
    <complexContent>
      <extension base="target:Vehicle"/>
      <sequence>
        <element name="wingspan" type="integer"/>
      </sequence>
    </complexContent>
  </complexType>      
</schema>

и следующее определение «meansOfTravel»:

<complexType name="MeansOfTravel">
  <complexContent>
    <sequence>        
      <element name="transport" type="target:Vehicle"/>        
    </sequence>
  </complexContent>
</complexType>

<element name="meansOfTravel" type="target:MeansOfTravel"/>

С этим определением вам нужно указать тип вашего экземпляра, используя xsi:type, например:

<meansOfTravel>
  <transport xsi:type="Plane">
     <wingspan>3</wingspan>
  </transport>
</meansOfTravel>

Я просто хотел бы получить сопоставление "имя типа" - "имя элемента", чтобы его можно было заменить только

<meansOfTravel>
  <plane>
    <wingspan>3</wingspan>
  </plane>
</meansOfTravel>

Единственный способ, которым я мог сделать это до сих пор, - сделать это явным:

<complexType name="MeansOfTravel">
  <sequence>        
    <choice>
      <element name="plane" type="target:Plane"/>
      <element name="car" type="target:Car"/>         
    </choice>
  </sequence>
</complexType>

<element name="meansOfTravel" type="target:MeansOfTravel"/>

Но это означает, что я должен перечислить все возможные подтипы в сложном типе «MeansOfTravel». Нет ли способа заставить синтаксический анализатор XML предположить, что вы имеете в виду «Плоскость», если вы называете элемент «плоскостью»? Или я должен сделать выбор явным? Я просто хотел бы сохранить свой дизайн СУХИМ - если у вас есть какие-либо другие предложения (например, группы или что-то в этом роде) - я весь слушаю.


person Alexander Torstling    schedule 01.06.2010    source источник


Ответы (1)


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

К сожалению, элементы группы замещения должны быть определены как глобальные элементы. Итак, у вас будет это:

<complexType name="MeansOfTravel">
  <complexContent>
    <sequence>        
      <element ref="transport"/>
    </sequence>
  </complexContent>
</complexType>

<element name="transport" type="target:Vehicle"/>
<element name="plane" type="target:Plane" substitutionGroup="target:transport"/>

Затем в вашем XML-документе вы можете использовать:

<meansOfTravel>
    <plane>...</plane>
</meansOfTravel>

Подробнее о группах замещения здесь. И нет, парсер, к сожалению, не может этого догадаться, поэтому вам все равно придется перечислять элементы :( Однако есть одно преимущество перед выбором: схему можно расширить извне, импортировав ее, не изменяя ее. Выбор не может быть расширен .

person xcut    schedule 01.06.2010
comment
Спасибо, это выглядит аккуратно. Есть ли какие-либо другие преимущества использования этого перед выбором, кроме аргумента расширения? Я спрашиваю, потому что это выглядит довольно занято, и мне интересно, будет ли выбор более логичным выбором (без каламбура), учитывая удобочитаемость. - person Alexander Torstling; 01.06.2010
comment
Если бы вся схема была под вашим контролем, я бы пошел на выбор. Помимо прочего, он упрощает чтение классов, созданных с помощью привязки данных, и позволяет избежать введения всех этих глобальных элементов. - person xcut; 01.06.2010
comment
В порядке. Выбор это. Еще раз спасибо. - person Alexander Torstling; 01.06.2010