2009-05-20 6 views
5

Я следующую схемуJAXB Список выбора

<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 генерирует класс с двумя КНИЖНАЯ ПОЛКА списков, один для 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 генерирует только с КНИЖНАЯ ПОЛКА один список newBookOrOldBook типа List<JAXBElement<String>>.

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

+0

Разъяснения: вы хотите тот же класс, как в примере одной, но с использованием схемы в примере два? (и, конечно, списки могут иметь разную длину). – 13ren

+0

Кроме того, что-то случилось с вашим синтаксисом в «List>» - вы, вероятно, не указали '' для ускорения кода inline. – 13ren

ответ

0

Возможно, что-то вроде этого?

<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> 
+0

Спасибо за ваш ответ. Извините, но в моем вопросе неясно. Как oldBook, так и newBook ​​будут содержать общие поля, а также разные, и я хочу избежать кастинга в Java-коде. В схеме, описанной выше, когда oldBook и newBook ​​имеют строковый тип, JAXB будет генерировать List of JAXBElement , и вместо экземпляра instanceof и литья нужно вызвать getName на JAXBElement для определения требуемого типа элемента. Возможно, эта ситуация неверна для дизайна XML? И я должен отделить список oldBook и newBook? – olek

+0

Возможно, у вас может возникнуть проблема с чрезмерной вероятностью. Я не так много знаю о JAXB и возможности сформировать объектную модель, созданную из XSD. Выделение данных одного и того же типа по имени элемента требует, чтобы ваша программа вызывала getName(). Если вы измените форму схемы, вы можете использовать , и в этом случае вам не нужно будет вызывать getName(). Вместо этого у вас будет другая объектная модель. Или вы можете указать новые complexTypes для newBook ​​и oldBook, как в моей первой примерной схеме. Тебе решать. – Cheeso

0

Я не думаю, что это возможно в JAXB, без написания некоторых пользовательских Ja или 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, но я думаю, что он будет генерировать список от класс с двумя полями, новыйBook и старыйBook. Таким образом, вам не нужно бросать или использовать instanceof, но можете просто проверить нуль, чтобы узнать, какой из них он есть. Как я уже сказал, это не решение, но, возможно, немного ближе.

-1

Я думаю, что я должен отказаться от идеи смешивания списков разных элементов в одном элементе (смешение старых и новых книг с книгой), тем более, что я планирую ссылаться на списки этих элементов (новые и старые списки книг) в других элементах. Если я этого не сделаю, это быстро станет кошмаром в 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-документу.

2

Вы можете использовать Simplify plugin от JAXB2 Basics. Он может упростить свойства @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;