2009-05-20 19 views
5

He siguiente esquemaLista JAXB de elección

<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 clase estantería con dos listas, una para newBook ​​y uno para OLDBOOK. ¡Excelente!

Ahora quiero que los libros aparezcan en cualquier orden. Así que vuelvo a escribir mi esquema para:

<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 estantería con una sola lista newBookOrOldBook de tipo List<JAXBElement<String>>.

No me importa el orden en que aparecen los libros y quiero permitir que el escritor XML especifique los libros en el orden que desee, pero igual quiero libros de cada tipo como List en la clase BookShelf generada. ¿Hay alguna manera de que pueda lograr esto?

+0

Aclaración: desea que la misma clase que en el ejemplo uno, pero utilizando el esquema en el ejemplo dos? (y, por supuesto, las listas pueden ser de diferentes longitudes) – 13ren

+0

Además, algo le sucedió a su sintaxis en "Lista>" - probablemente dejó fuera '' para escapar del código en línea. – 13ren

Respuesta

0

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 que podría 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> 
+0

Gracias por su respuesta. Lo siento, pero no estaba claro en mi pregunta. Tanto el libro antiguo como el libro nuevo contendrán campos comunes y diferentes, y quiero evitar el uso de código Java. En el esquema descrito anteriormente, cuando oldBook y newBook ​​tienen el tipo de cadena, JAXB generará la Lista de JAXBElement y en lugar de instanceof y fundición, uno debe llamar a getName en JAXBElement para determinar el tipo de elemento requerido. ¿Puede ser que esta situación sea incorrecta para el diseño XML? ¿Y debería separar la enumeración de libros antiguos y libros nuevos? – olek

+0

Puede que tengas un problema excesivo, sospecho. No sé mucho sobre JAXB y la posibilidad de dar forma al modelo de objetos generado a partir del XSD. Distinguir datos del mismo tipo por nombre de elemento solo requiere que su programa llame a getName(). Si cambia la forma del esquema, podría usar , en cuyo caso no tendría que llamar a getName(). En cambio, tendrías un modelo de objeto diferente. O podría especificar nuevos complexTypes para newBook ​​y oldBook, como en mi primer esquema de ejemplo. Tu decides. – Cheeso

0

No creo que esto es posible en JAXB, sin necesidad de escribir alguna Java o XSLT personalizado.

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.

El siguiente no no responde a su pregunta, pero tal vez es un paso hacia lo que quiere:

<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 va a generar una lista de una clase con dos campos, nuevaLibro y anteriorLibro. Por lo tanto, no tiene que emitir o usar instanceof, pero solo puede verificar null para ver cuál es. Como dije, es no una solución, pero tal vez un poco más cerca.

-1

Creo que tengo que rechazar la idea de mezclar listas de diferentes elementos en un elemento (mezclar libros antiguos 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.

2

Puede usar el Simplify plugin desde JAXB2 Basics. Puede simplificar las propiedades @XmlElements y @XmlElementRefs, lo que hace las cosas mucho más fáciles, si realmente no le importa el orden.He aquí 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> 

Normalmente, esto generará una propiedad como:

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

Usted puede utilizar el elemento simplify:as-element-property para remodelar este propiedad compleja como propiedades de dos elementos o simplify:as-reference-property como dos propiedades de referencia.

No es que en el caso de una propiedad de referencia, debe personalizar uno de los xs:element y no el 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;