2016-05-23 27 views
5

C'è un XML fornito dal produttore come questo:JAXB e XML namespace-meno

<?xml version="1.0" encoding="utf-8"?> 
<Foo> 
    <Bar>...</Bar> 
    <Bar>...</Bar> 
</Foo> 

Nota non v'è alcuna dichiarazione xmlns="...", né il venditore fornisce uno schema. Questo non può essere modificato e il fornitore continuerà a spedire XML come questo in futuro.

Per generare attacchi JAXB, ho creato uno schema come questo:

<?xml version="1.0" encoding="utf-8"?> 
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
      targetNamespace="http://acme.com/schema" 
      xmlns:tns="http://acme.com/schema" 
      elementFormDefault="qualified"> 
    <xsd:element name="Foo"> 
     <xsd:complexType> 
      <xsd:sequence> 
       <xsd:element ref="tns:Bar" maxOccurs="unbounded"/> 
      </xsd:sequence> 
     </xsd:complexType> 
    </xsd:element> 
    <xsd:element name="Bar"> 
     ... 
    </xsd:element> 
</xsd:schema> 

Nota che ho dichiarato uno spazio dei nomi più o meno significativo ("http://acme.com/schema") in modo che potrebbe essere utilizzato per l'elemento riferimenti, ecc XJC genera il seguente package-info.java:

@javax.xml.bind.annotation.XmlSchema(namespace = "http://acme.com/schema", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) 
package com.acme.schema; 

poi cerco di unmarshal documento XML:

JAXBContext jaxb = JAXBContext.newInstance("com.acme.schema"); 
Unmarshaller unmarshaller = jaxb.createUnmarshaller(); 
InputStream is = this.getClass().getClassLoader().getResourceAsStream("test.xml"); 

InputSource source = new InputSource(is); 
Foo foo = (Foo) unmarshaller.unmarshal(source); 
.210

Ecco l'eccezione ottengo:

javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"Foo"). Expected elements are <{http://acme.com/schema}Foo>,...> 

Ovviamente, questo accade perché gli elementi XML appartengono a uno spazio dei nomi vuoto, mentre le classi JAXB hanno una non-vuoto.

C'è un modo per simulare uno spazio dei nomi XML (probabilmente durante l'analisi XML), in modo che JAXB possa riconoscere gli elementi e vincolarli correttamente? Le soluzioni SAX/StAX sarebbero preferite rispetto al DOM, perché i documenti XML potrebbero essere piuttosto grandi.

+0

ti dispiacerebbe mettere classi generate da XJC su? –

risposta

2

Innanzitutto, non consiglierei tutto questo. L'integrazione con un'API di terze parti è abbastanza complicata senza aggiungere ulteriori complicazioni. Perché preoccuparsi di aggiungere uno spazio dei nomi? Non sono sicuro di cosa ne ricaverai. Pensa alla persona fortunata che erediterà il tuo codice base. Vedranno l'aggiunta dello spazio dei nomi ma non hanno idea del perché lo stai facendo.

Vorrei fare un ulteriore passo avanti e suggerisco di evitare completamente lo schema e di usare solo POJO annotati. Tutti questi passaggi aggiungono solo complicazioni, fasi di creazione, ecc.

Tuttavia, se sei determinato, questo sembra il caso per eccellenza delle trasformazioni XSL. È possibile trovare una trasformazione XSL che aggiunge spazi dei nomi abbastanza facilmente, come ad esempio this question Poi si tratta di una semplice questione di cablaggio vostra trasformazione in JAXB ...

private static Foo unmarshalDocument(InputStream xslStream, InputStream xmlStream) throws Exception { 
    StreamSource stylesource = new StreamSource(xslStream); 
    StreamSource inputStream = new StreamSource(xmlStream); 
    Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource); 
    JAXBResult result = new JAXBResult(context); 
    transformer.transform(inputStream, result); 
    return (Foo) result.getResult(); 
} 
+0

In effetti, si è scoperto che lo spazio dei nomi non era affatto necessario. (Approfondimenti: O'Reilly "XML Schema", Cap. 10, "Controlling Namespaces".) Ho messo a fuoco quel 'targetNamespace =', 'xmlns: tns =' attributi e 'tns:' i prefissi, e il problema è andato lontano. –

+0

Come per XJC vs POJO - Ho mostrato solo un frammento di XML, i documenti reali sono molto più complessi; i POJO con annotazioni fatte a mano sarebbero un overkill qui. Invece, abbiamo utilizzato l'eccellente designer di schemi di NetBeans XML Tools, applicato personalizzazioni JAXB minime e voilà. Questo è stato un risparmio in tempo reale. Per quanto riguarda il processo di compilazione, è guidato da Maven + [maven-jaxb2-plugin] (https://github.com/highsource/maven-jaxb2-plugin), quindi tutta la complessità è nascosta. Tuttavia, ricordo situazioni in cui le classi generate da XJC richiedevano una significativa personalizzazione manuale, quindi l'idea della rigenerazione fu respinta. –