impl - xsd to java jaxb
Lista de elección de JAXB (4)
Tengo el siguiente esquema
<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 genera la clase BookShelf con dos listas, una para newBook y otra para oldBook. ¡Excelente!
Ahora quiero que los libros aparezcan en cualquier orden. Entonces reescribo mi esquema a:
<complexType name="BookShelf">
<sequence>
<choice minOccurs="0" maxOccurs="unbounded">
<element name="newBook" type="string"/>
<element name="oldBook" type="string"/>
</choice>
</sequence>
</complexType>
Pero ahora XJC genera BookShelf con solo una lista newBookOrOldBook de tipo List<JAXBElement<String>>
.
No me importa el orden en que aparecen los libros y deseo permitir que el escritor XML especifique los libros en el orden que él desee, pero igual quiero libros de cada tipo como Lista en la clase BookShelf generada. ¿Hay alguna manera de que pueda lograr esto?
Tal vez algo como esto?
<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>
Por supuesto, podrías simplificar a
<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>
Creo que tengo que rechazar la idea de mezclar listas de diferentes elementos en un elemento (mezclar libros viejos y nuevos en un libro), especialmente porque estoy planeando hacer una lista de esos elementos (listas de libros nuevos y viejos) en otros elementos . Si no lo hago, se convirtió rápidamente en una pesadilla en el código de Java. Terminé con el siguiente esquema:
<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>
Gracias a todos por ayudarme a darme cuenta de esto. Este esquema conducirá a un código Java más claro y simple, así como a un documento XML más legible y predecible.
No creo que esto sea posible en JAXB, sin escribir algunos Java o XSLT personalizados.
JAXB no es muy bueno en el mapeo entre objetos y xml que tienen una estructura diferente, como la tuya. Además, el pedido del libro anterior con respecto a los libros nuevos en XML se perderá cuando se convierta en dos listas separadas en Java, y JAXB generalmente quiere preservar la información.
Lo siguiente no responde su pregunta, pero tal vez sea un paso hacia lo que desea:
<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>
No he probado esto con JAXB, pero creo que generará una lista de una clase con dos campos, newBook y oldBook . Por lo tanto, no tiene que emitir o usar instanceof, pero solo puede verificar null para ver cuál es. Como dije, no es una solución, pero tal vez un poco más cerca.
Puede usar el complemento Simplify de JAXB2 Basics . Puede simplificar las propiedades @XmlElements
y @XmlElementRefs
, lo que facilita mucho las cosas, si realmente no le importa el orden. Aquí hay un ejemplo (extracto de la documentación):
Considere la siguiente opción:
<xs:complexType name="typeWithReferencesProperty">
<xs:choice maxOccurs="unbounded">
<xs:element name="a" type="someType"/>
<xs:element name="b" type="someType"/>
</xs:choice>
</xs:complexType>
Esto normalmente generará una propiedad como:
@XmlElementRefs({
@XmlElementRef(name = "a", type = JAXBElement.class),
@XmlElementRef(name = "b", type = JAXBElement.class)
})
protected List<JAXBElement<SomeType>> aOrB;
Puede usar el elemento simplify:as-element-property
para remodelar esta propiedad compleja como propiedades de dos elementos o simplify:as-reference-property
referencia como dos propiedades de referencia.
No es que en el caso de una propiedad de referencia, tenga que personalizar una de las xs:choice
xs:element
y no 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>
Resultados en:
@XmlElement(name = "a")
protected List<SomeType> a;
@XmlElement(name = "b")
protected List<SomeType> b;