2016-05-23 15 views
5

Es gibt eine vom Hersteller bereitgestellte XML wie folgt aus:JAXB und Namespace-less XML

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

Hinweis gibt es keine xmlns="..." Erklärung, noch der Verkäufer ein Schema liefern. Dies kann nicht geändert werden, und der Anbieter wird XML in Zukunft weiterhin so versenden.

JAXB Bindungen zu erzeugen, habe ich ein Schema wie folgt erstellt:

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

Bitte beachte, dass ich einen mehr oder weniger sinnvollen Namensraum deklariert haben („http://acme.com/schema“), so dass es für das Element verwendet werden könnte, Referenzen usw. XJC erzeugt die folgende package-info.java:

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

Dann versuche ich zu Abstellungs XML-Dokument:

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

Hier ist die Ausnahme, die ich erhalten:

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

Offensichtlich ist dies geschieht, weil XML-Elemente in einen leeren Namensraum gehören, während JAXB-Klassen eine nicht-leere haben.

Gibt es eine Möglichkeit, einen XML-Namespace zu fälschen (wahrscheinlich während des XML-Parsens), damit JAXB die Elemente erkennt und erfolgreich bindet? SAX/StAX-Lösungen würden gegenüber DOM bevorzugt, da XML-Dokumente ziemlich umfangreich sein könnten.

+0

würde es Ihnen etwas ausmachen Klassen von XJC auf erzeugt setzen? –

Antwort

2

Erstens würde ich all dies nicht empfehlen. Die Integration mit einer API eines Drittanbieters ist kompliziert genug, ohne zusätzliche Komplikationen hinzuzufügen. Warum sollten Sie überhaupt einen Namespace hinzufügen? Ich bin mir nicht sicher, was du daraus machst. Denken Sie an die glückliche Person, die Ihre Codebasis erbt. Sie werden den Namespace hinzufügen, wissen aber nicht, warum Sie das tun.

Ich würde sogar noch einen Schritt weiter gehen und vorschlagen, das Schema komplett zu vermeiden und nur kommentierte POJOs zu verwenden. Alle diese Schritte fügen nur Komplikation hinzu, bauen Schritte, etc.

Wenn Sie jedoch entschlossen sind, scheint dies der grundlegende Fall für XSL-Transformationen. Sie können eine XSL-Transformation fügt hinzu, dass Namespaces leicht genug, wie this question finden Dann ist es eine einfache Sache ist Ihre Umwandlung in JAXB verdrahten ...

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

Tatsächlich stellte sich heraus, dass der Namensraum überhaupt nicht notwendig war. (Weiterführende Literatur: O'Reilly "XML Schema", Kap. 10, "Namespaces kontrollieren".) Ich habe die 'targetNamespace =', 'xmlns: tns =' attributes und 'tns:' Präfixe mit einem Nuking versehen, und das Problem ging Weg. –

+0

Was XJC vs. POJO betrifft - ich habe nur einen Ausschnitt von XML gezeigt, die echten Dokumente sind viel komplexer; Handgemachte POJOs wären hier ein Overkill. Stattdessen haben wir den ausgezeichneten Schema-Designer aus den NetBeans XML-Tools, angewandte minimale JAXB-Anpassungen und voilà verwendet. Das war eine echte Zeiteinsparung. Wie beim Build-Prozess wird es von Maven + [maven-jaxb2-plugin] (https://github.com/highsource/maven-jaxb2-plugin) gesteuert, so dass die ganze Komplexität verborgen ist. Ich erinnere mich jedoch an Situationen, in denen XJC-generierte Klassen eine erhebliche manuelle Anpassung erforderten, weshalb die Idee der Regeneration abgelehnt wurde. –