2009-12-30 4 views
22

Zum Beispiel habe ich ein einfaches Schema, das ein anderes Schema importiert. Das zweite Schema (urn: just: attributes, just-attributes.xsd) definiert nur eine Attributgruppe.Ist es möglich, das Namespace-Präfix anzupassen, das JAXB beim Marshalling zu einem String verwendet?

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

Ich verwende die Metro xjc Ant Aufgabe, um Klassen aus diesem Schema zu generieren. Das Problem, auf das ich stoße, ist, dass die Third-Party-Anwendung, mit der ich interagiere, merkwürdig in Bezug auf Namespaces ist. In diesem Fall brauche ich einen String-Wert, also muss ich ihn serialisieren. Ich verwende hierfür den Standardcode.

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(); 
} 

Was mir etwas entlang der Linien von

<?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"/> 

Ich habe das Problem gibt, ist, dass diese dritte Partei so etwas wie xmlns:thirdpartyns="urn:just:attributes" erwartet, was zu sagen ist, parsen sie basierend auf den Namen dem Namensraum gegeben. Es hat zu "Drittparteien" für ihre Software zu arbeiten.

Kennt jemand einen Weg um dies zu tun, kurz eine Suche und ersetzen in der resultierenden Zeichenfolge? Eine benutzerdefinierte Bindungsregel vielleicht?

Antwort

26

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

Dies zeigt, wie es zu tun. Ein weiterer

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

Key-Bits in dem Fall, dass Link stirbt auch:

die NamespacePrefixMapper Klasse, in dem com.sun.xml.bind.marshaller Paket gefunden. Die abstrakte Klasse eine Methode hat zu implementieren:

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

dann

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

Wenn Sie mit javax.xml.xpath.XPath auch, Ihre NamespacePrefixMapper können auch javax.xml.namespace.NamespaceContext implementieren Zentralisierung der Namensraumanpassung in einer einzigen Klasse

+0

Dank. Das funktioniert wie ein Zauber! –

+0

Die Verbindung ist unterbrochen. –

+0

Der Link ist tot ... @DaveC bitte überprüfen Sie es! – basZero

0

Es gibt eine Möglichkeit, dies zu tun, die eine interne JAXB-Implementierungsklasse namens NamespacePrefixMapper verwendet. In der JAXB RI ist dies in com.sun.xml.bind.marshaller, aber in Java6 ist es in com.sun.xml.internal.bind.marshaller.

Dies ist eine abstrakte Klasse, in der Sie die abstrakte Methode, die Namespace-URIs auf Präfixe zuordnet, ableiten und implementieren können.

Sie dann eine Instanz dieser Unterklasse in die Einweiser injizieren:

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

Der Eigenschaftsname für die Java6 Version anders sein wird, aber Sie bekommen die Idee.

Beachten Sie, dass dies eine interne JAXB-Implementierungsklasse ist, es gibt also keine Garantie, dass sie in zukünftigen Versionen vorhanden sein wird.

+1

Bitte unterklassifizieren Sie nicht die 'interne' Klasse. – Barett

11

I getestet that in Java SE6 und es erfordert eine kleine Änderung im Vergleich zu der Lösung für Java SE 5 (wie above beschrieben):

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

So ist die dritte Eigenschaft von oben enthält die zusätzlichen .internal. in der Paketname im Vergleich zur Java SE5-Version. Was ich noch nicht herausgefunden habe, ist, wie man dem Marshaller sagt, welcher Namespace-URI zum Standard-Namespace ("") wird. Wenn ich die Methode getPreferredPrefix() überschreibe und eine leere Zeichenfolge zurücksende, hat der Marshaller Probleme mit dem Schreiben von Attributen des Standardnamespace (in diesem Fall erstellt er einen neuen Namespace namens ns1)

+2

Anscheinend in Java SE 7, verwendet es wieder "com.sun.xml.bind.namespacePrefixMapper" .... (mit der Java SE 6 Eigenschaft bekomme ich eine Ausnahme) – edbras

+2

Weiß jemand, wie es für Java SE korrekt wäre 8? @edbras – basZero

5

Ich hatte die gleiche Frage. In package-info.java (wenn Sie es nicht haben, können Sie einfach manuell erstellen) fügen Sie den xmlns Teil:

@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

Was passiert, wenn ich Quellen von xsd erzeuge? Apache Plugin Maven verwenden. Wie kann ich es so anpassen? –

Verwandte Themen