JAXB Список выбора - PullRequest
       15

JAXB Список выбора

5 голосов
/ 20 мая 2009

У меня есть следующая схема

<complexType name="BookShelf">
   <sequence>
      <element name="newBook" type="string" minOccurs="0" maxOccurs="unbounded"/>
      <element name="oldBook" type="string" minOccurs="0" maxOccurs="unbounded"/>
   </sequence>
</complexType>

XJC генерирует класс BookShelf с двумя списками, один для newBook ​​и один для oldBook. Отлично!

Теперь я хочу, чтобы книги появлялись в любом порядке. Поэтому я переписываю свою схему так:

<complexType name="BookShelf">
   <sequence>
      <choice minOccurs="0" maxOccurs="unbounded">
         <element name="newBook" type="string"/>
         <element name="oldBook" type="string"/>
      </choice>
   </sequence>
</complexType>

Но теперь XJC генерирует BookShelf только с одним списком newBookOrOldBook типа List<JAXBElement<String>>.

Меня не волнует порядок, в котором появляются книги, и я хочу, чтобы редактор XML мог указывать книги в любом порядке, который он / она желает, но я все еще хочу, чтобы книги каждого типа представляли собой List в сгенерированном классе BookShelf. Есть ли способ, которым я могу достичь этого?

Ответы [ 4 ]

2 голосов
/ 26 марта 2012

Вы можете использовать плагин Упрощение из Основы JAXB2 . Он может упростить свойства @XmlElements и @XmlElementRefs, что значительно облегчает задачу, если вы действительно не заботитесь о заказе. Вот пример (выдержка из документации):

Рассмотрим следующий выбор:

<xs:complexType name="typeWithReferencesProperty">
    <xs:choice maxOccurs="unbounded">
        <xs:element name="a" type="someType"/>
        <xs:element name="b" type="someType"/>
    </xs:choice> 
</xs:complexType>

Обычно это генерирует свойство, подобное:

@XmlElementRefs({
    @XmlElementRef(name = "a", type = JAXBElement.class),
    @XmlElementRef(name = "b", type = JAXBElement.class)
})
protected List<JAXBElement<SomeType>> aOrB;

Вы можете использовать элемент simplify:as-element-property для изменения этого сложного свойства в качестве двух свойств элемента или simplify:as-reference-property в качестве двух ссылочных свойств.

Не то чтобы в случае ссылочного свойства вы должны настроить один из xs:element, а не xs:choice.

<xs:complexType name="typeWithReferencesProperty">
    <xs:choice maxOccurs="unbounded">
        <xs:element name="a" type="someType">
            <xs:annotation>
                <xs:appinfo>
                    <simplify:as-element-property/>
                </xs:appinfo>
            </xs:annotation>
        </xs:element>
        <xs:element name="b" type="someType"/>
    </xs:choice> 
</xs:complexType>

Результаты:

@XmlElement(name = "a")
protected List<SomeType> a;
@XmlElement(name = "b")
protected List<SomeType> b;
0 голосов
/ 21 мая 2009

Я не думаю, что это возможно в JAXB, без написания некоторого пользовательского Java или XSLT.

JAXB не очень хорош в отображении между объектами и xml, которые имеют различную структуру, как ваша. Кроме того, упорядочение старой книги относительно новых книг в XML будет потеряно при преобразовании в два отдельных списка в Java, и JAXB обычно хочет сохранить информацию.

Следующее не отвечает на ваш вопрос, но, возможно, это шаг к тому, что вы хотите:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="bookShelf" type="BookShelf"/>
  <xs:complexType name="BookShelf">
    <xs:sequence>
      <xs:sequence minOccurs="0" maxOccurs="unbounded">
        <xs:element name="newBook" minOccurs="0" type="xs:string"/>
        <xs:element name="oldBook" minOccurs="0" type="xs:string"/>
      </xs:sequence>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

Я не пробовал это с JAXB, но думаю, что он сгенерирует список класса с двумя полями, newBook ​​ и oldBook . Таким образом, вам не нужно приводить или использовать instanceof, но вы можете просто проверить на null, чтобы увидеть, какой это. Как я уже сказал, это не решение, но, возможно, немного ближе.

0 голосов
/ 21 мая 2009

Я думаю, что должен отказаться от идеи смешивать списки различных элементов в одном элементе (смешивая старые и новые книги в самой книге), особенно потому, что я планирую ссылаться на списки этих элементов (списки новых и старых книг) в других элементах. Если я этого не сделаю, это быстро станет кошмаром в Java-коде. Я закончил со следующей схемой:

<schema
   xmlns="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://www.example.org/books"
   targetNamespace="http://www.example.org/books"
   elementFormDefault="qualified"
>
   <complexType name="BookShelf">
      <sequence>
         <element name="newBooks" type="tns:NewBookList" minOccurs="0" />
         <element name="oldBooks" type="tns:OldBookList" minOccurs="0" />
      </sequence>
   </complexType>

   <complexType name="NewBookList">
      <sequence>
         <element name="newBook" type="tns:NewBook" maxOccurs="unbounded" />
      </sequence>
   </complexType>

   <complexType name="OldBookList">
      <sequence>
         <element name="oldBook" type="tns:OldBook" maxOccurs="unbounded" />
      </sequence>
   </complexType>

   <complexType name="NewBook" />
   <complexType name="OldBook" />
</schema>

Спасибо всем, кто помог мне понять это. Эта схема приведет к более ясному и простому Java-коду, а также к более читаемому и предсказуемому XML-документу.

0 голосов
/ 20 мая 2009

Может как то так?

<schema 
   elementFormDefault = "qualified" 
   xmlns              = "http://www.w3.org/2001/XMLSchema"
   xmlns:xs           = "http://www.w3.org/2001/XMLSchema"
   xmlns:tns          = "urn:cheeso.examples.2009.05.listofbooks" 
   targetNamespace    = "urn:cheeso.examples.2009.05.listofbooks" 
  >

  <element name="Shelf" nillable="true" type="tns:BookShelf" />

  <complexType name="BookShelf">
    <sequence>
      <element minOccurs="0" maxOccurs="1" name="Store" type="tns:ArrayOfChoice1" />
    </sequence>
  </complexType>

  <complexType name="ArrayOfChoice1">
    <choice minOccurs="0" maxOccurs="unbounded">
      <element minOccurs="1" maxOccurs="1" name="newBook" nillable="true" type="tns:newBook" />
      <element minOccurs="1" maxOccurs="1" name="oldBook" nillable="true" type="tns:oldBook" />
    </choice>
  </complexType>

  <complexType name="Book">
    <attribute name="name" type="string" />
  </complexType>

  <complexType name="newBook">
    <complexContent mixed="false">
      <extension base="tns:Book" />
    </complexContent>
  </complexType>

  <complexType name="oldBook">
    <complexContent mixed="false">
      <extension base="tns:Book" />
    </complexContent>
  </complexType>

</schema>

Конечно, вы можете упростить до

<schema 
   elementFormDefault = "qualified" 
   xmlns              = "http://www.w3.org/2001/XMLSchema"
   xmlns:xs           = "http://www.w3.org/2001/XMLSchema"
   xmlns:tns          = "urn:cheeso.examples.2009.05.listofbooks" 
   targetNamespace    = "urn:cheeso.examples.2009.05.listofbooks" 
  >

  <element name="Shelf" nillable="true" type="tns:BookShelf" />

  <complexType name="BookShelf">
    <sequence>
      <element minOccurs="0" maxOccurs="1" name="Store" type="tns:ArrayOfChoice1" />
    </sequence>
  </complexType>

  <complexType name="ArrayOfChoice1">
    <choice minOccurs="0" maxOccurs="unbounded">
      <element minOccurs="1" maxOccurs="1" name="newBook" nillable="true" type="xs:string" />
      <element minOccurs="1" maxOccurs="1" name="oldBook" nillable="true" type="xs:string" />
    </choice>
  </complexType>

</schema>
...