2009-12-30 12 views
22

Ad esempio, ho uno schema semplice che importa un altro schema. Il secondo schema (urn: just: attributes, just-attributes.xsd) definisce semplicemente un gruppo di attributi.È possibile personalizzare il prefisso dello spazio dei nomi che JAXB utilizza quando si esegue il marshalling su una stringa?

<?xml version="1.0" encoding="UTF-8"?> 
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://www.example.org/MySchema" 
    xmlns:tns="http://www.example.org/MySchema" 
    elementFormDefault="qualified" 
    xmlns:ja="urn:just:attributes"> 

    <import schemaLocation="just-attributes.xsd" namespace="urn:just:attributes"/> 

    <element name="MyElement"> 
     <complexType> 
      <attributeGroup ref="ja:AttributeGroup"/> 
     </complexType> 
    </element> 
</schema> 

Sto utilizzando l'attività Metro xjc Ant per generare classi fuori da questo schema. Il problema che sto incontrando è che l'applicazione di terze parti con cui sto interagendo è peculiare dei namespace. In questo caso ho bisogno di un valore di stringa, quindi devo serializzarlo. Per questo utilizzo il codice boilerplate.

private static <T> String marshal(T object) throws JAXBException{ 
    OutputStream outputStream = new ByteArrayOutputStream(); 
    JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass()); 
    Marshaller marshaller = jaxbContext.createMarshaller(); 
    marshaller.marshal(object, outputStream); 
    return outputStream.toString(); 
} 

Il che mi dà qualcosa sulla falsariga di

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<ns2:MyElement xmlns:ns1="urn:just:attributes" xmlns:ns2="http://www.example.org/MySchema" ns1:attrib1="1234" ns1:attrib2="5678"/> 

Il problema che ho è che questa terza parte si aspetta qualcosa di simile xmlns:thirdpartyns="urn:just:attributes", vale a dire, sono l'analisi di base al nome dato al namespace. Lo ha il valore di come "terze parti" perché il loro software funzioni.

Qualcuno sa di un modo per aggirare questo, a corto di fare un trovare e sostituire nella stringa risultante? Una regola di bind personalizzata forse?

risposta

26

http://hwellmann.blogspot.com/2011/03/jaxb-marshalling-with-custom-namespace.html

Questo dimostra come farlo.

altro: http://www.systemmobile.com/?p=280

bit chiave nel caso in cui il collegamento muore troppo:

classe NamespacePrefixMapper, che si trova nel pacchetto com.sun.xml.bind.marshaller. La classe astratta ha un metodo per implementare:

public abstract String getPreferredPrefix( 
    String namespaceUri,   
    String suggestion,   
    boolean requirePrefix); 

poi

Marshaller marshaller =   
    jaxbContext.createMarshaller();   
marshaller.setProperty(”com.sun.xml.bind.namespacePrefixMapper”,   
    new MyNamespacePrefixMapper()); 

Se si sta utilizzando anche javax.xml.xpath.XPath, il vostro NamespacePrefixMapper può anche implementare javax.xml.namespace.NamespaceContext , centralizzando la personalizzazione dello spazio dei nomi in una singola classe.

+0

Grazie. Funziona come un fascino! –

+0

Il link è rotto. –

+0

Il link è morto ... @DaveC si prega di controllare! – basZero

0

C'è un modo per farlo, che utilizza una classe di implementazione JAXB interna denominata NamespacePrefixMapper. Nel RI JAXB, questo è in com.sun.xml.bind.marshaller, ma in Java6 è in com.sun.xml.internal.bind.marshaller.

Questa è una classe astratta, che è possibile sottoclasse e implementa il metodo astratto che associa gli URI dello spazio dei nomi ai prefissi.

È quindi inietta un'istanza di tale sottoclasse nella marshaller:

JAXBContext context = ... 
Marshaller marshaller = context.createMarshaller(); 
NamespacePrefixMapper prefixMapper = new MyPrefixMapperImpl(); 
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", prefixMapper); 

Il nome della proprietà sta per essere diverso per la versione java6, ma si ottiene l'idea.

Si noti che questa è una classe di implementazione JAXB interna, quindi non c'è garanzia che sarà presente nelle versioni future.

+1

Si prega di non sottoclasse la classe 'internal'. – Barett

11

ho testato that in Java SE6 e richiede un piccolo cambiamento rispetto alla soluzione per Java SE 5 (come descritto above):

Marshaller m = context.createMarshaller(); 
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 
    m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); 
    m.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", mapper); 

Quindi la terza proprietà dall'alto contiene le ulteriori .internal. in il nome del pacchetto rispetto alla versione Java SE5. Quello che non ho ancora scoperto è come dire a Marshaller quale URI dello spazio dei nomi diventa lo spazio dei nomi predefinito (""). Se eseguo l'override del metodo getPreferredPrefix() e restituisco una stringa vuota, Marshaller presenta problemi con la scrittura degli attributi dello spazio dei nomi predefinito (in questo caso crea un nuovo spazio dei nomi chiamato ns1)

+2

Apparentemente in java SE 7, utilizza nuovamente "com.sun.xml.bind.namespacePrefixMapper" .... (con la proprietà Java SE 6 ottengo un'eccezione) – edbras

+2

Qualcuno sa come sarebbe corretto per Java SE 8? @edbras – basZero

5

Ho avuto la stessa domanda. In package-info.java (se non lo avete, si può semplicemente creare manualmente) aggiungere la parte xmlns:

@javax.xml.bind.annotation.XmlSchema(xmlns = { 
     @javax.xml.bind.annotation.XmlNs(namespaceURI = "urn:just:attributes", prefix = "thirdpartyns") }, 
     elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) 
+1

Cosa succede se generi sorgenti da xsd? Usando il plugin apache Maven. Come posso personalizzarlo in questo modo? –

Problemi correlati