2009-05-20 8 views
5

Ho seguente schemaJAXB Lista di scelta

<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 classe libreria con due liste, una per newBook ​​e uno per oldbook. Eccellente!

Ora voglio che i libri appaiano in qualsiasi ordine. Così riscrivo il mio schema per:

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

Ma ora XJC genera libreria con una sola lista newBookOrOldBook di tipo List<JAXBElement<String>>.

Non mi interessa l'ordine in cui i libri vengono visualizzati e voglio consentire a XML writer di specificare i libri nell'ordine che preferisce, ma desidero comunque che i libri di ogni tipo siano List nella classe BookShelf generata. C'è un modo per riuscirci?

+0

precisazione: si desidera che la stessa classe come nell'esempio uno, ma utilizzando lo schema di esempio due? (e, naturalmente, le liste possono essere di lunghezze diverse) – 13ren

+0

Inoltre, qualcosa è successo alla tua sintassi in "Lista>" - probabilmente hai omesso '' per il codice di escape inline. – 13ren

risposta

0

Forse qualcosa del genere?

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

Naturalmente si potrebbe semplificare al

<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

Grazie per la risposta. Scusa, ma non sono stato chiaro nella mia domanda. Sia oldBook che newBook ​​conterranno campi comuni e diversi e voglio evitare di eseguire il cast in codice Java. Nello schema descritto sopra, quando oldBook e newBook ​​hanno il tipo di stringa, JAXB genererà l'elenco di JAXBElement e invece di instanceof e casting si deve chiamare getName su JAXBElement per determinare il tipo di elemento richiesto. Può essere che questa situazione sia errata per la progettazione XML? E dovrei separare l'enumerazione oldBook e newBook? – olek

+0

Potrei avere un problema sovraccosto, sospetto. Non so molto di JAXB e della possibilità di modellare il modello di oggetto generato dall'XSD. Distinguere i dati dello stesso tipo solo con il nome dell'elemento, richiede che il programma invochi il nome getName(). Se si modifica la forma dello schema, è possibile utilizzare , nel qual caso non è necessario chiamare getName(). Invece avresti un modello di oggetto diverso. Oppure puoi specificare nuovi complexTypes per newBook ​​e oldBook, come nel mio primo schema di esempio. Tocca a voi. – Cheeso

0

Non credo che questo è possibile in JAXB, senza scrivere alcuni java personalizzato o XSLT.

JAXB non è molto bravo a mappare tra oggetti e xml che hanno una struttura diversa, come la tua. Inoltre, l'ordinamento del vecchio libro rispetto ai nuovi libri in XML andrebbe perso quando convertito in due elenchi separati in Java e in genere JAXB vuole conservare le informazioni.

Il seguente fa non risponde alla tua domanda, ma forse è un passo verso ciò che si vuole:

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

Non ho provato questo con JAXB, ma penso che genererà un elenco di una classe con due campi, newBook ​​ e oldBook. Pertanto, non è necessario eseguire il cast o utilizzare instanceof, ma è sufficiente verificare null per vedere quale è. Come ho detto, è non una soluzione, ma forse un po 'più vicina.

-1

Penso di dover rifiutare l'idea di unire liste di elementi diversi in un unico elemento (mescolare vecchi e nuovi libri su un libro), soprattutto perché sto pianificando di fare riferimento a elenchi di tali elementi (elenchi di libri vecchi e nuovi) in altri elementi. Se non lo faccio diventa rapidamente un incubo nel codice java. Mi sono concluso con il seguente schema:

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

Grazie a tutti per avermi aiutato a realizzare questo. Questo schema porterà a un codice Java più chiaro e semplice, nonché a un documento XML più leggibile e prevedibile.

2

È possibile utilizzare Simplify plugin da JAXB2 Basics. Può semplificare le proprietà @XmlElements e @XmlElementRefs, il che rende le cose molto più semplici se non ti interessa veramente l'ordine.Ecco un esempio (estratto dalla documentazione):

Si consideri la seguente scelta:

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

Questo sarà normalmente genera una proprietà come:

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

È possibile utilizzare l'elemento simplify:as-element-property di rimodellare questo proprietà complessa come proprietà di due elementi o simplify:as-reference-property come due proprietà di riferimento.

Non che nel caso di una proprietà di riferimento, è necessario personalizzare uno degli xs:element e non lo 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> 

risultati in:

@XmlElement(name = "a") 
protected List<SomeType> a; 
@XmlElement(name = "b") 
protected List<SomeType> b;