2015-04-14 5 views
6

Ich benutze Jaxb2 und Spring. Ich versuche, XML zu entpacken, das von zwei meiner Kunden gesendet wird.Jaxb ignorieren den Namespace auf Unmarshalling

Bisher hatte ich nur einen Kunden zu handhaben, die einige xml wie folgt gesendet:

<foo xmlns="com.acme"> 
    <bar>[...]</bar> 
<foo> 

, die zu einem POJO wie diese gebunden ist:

@XmlType(name = "", propOrder = {"bar"}) 
@XmlRootElement(name = "Foo") 
public class Foo { 

    @XmlElement(name = "Bar") 
    private String bar; 

    [...] 
} 

Ich entdeckte, dass die vorherige Der Entwickler hat den Namensraum im Unmarshaller fest programmiert, damit er funktioniert.

Jetzt sendet der zweite Kunde das gleiche XML, ändert jedoch den Namespace!

<foo xmlns="com.xyz"> 
    <bar>[...]</bar> 
<foo> 

Offensichtlich schlägt die Unmarshaller entordnen, weil es einige {com.acme}foo statt {com.xyz}foo erwartet. Leider ist es nicht möglich, den Kunden zu bitten, das XML zu ändern.

Was ich versucht:

1) In application-context.xml, ich für eine Konfiguration gesucht, die mir erlauben würde, den Namensraum zu ignorieren, aber nicht finden konnte:

<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> 
    <property name="packagesToScan"> 
    <list> 
     <value>com.mycompany.mypkg</value> 
    </list> 
    </property> 
    <property name="marshallerProperties"> 
    <map> 
     <entry key="???"><value type="java.lang.Boolean">false</value></entry> 
    </map> 
    </property> 
</bean> 

es scheint, dass Die einzigen verfügbaren Optionen sind diejenigen, die im Javadoc von Jaxb2Marshaller aufgeführt sind:

/** 
* Set the JAXB {@code Marshaller} properties. These properties will be set on the 
* underlying JAXB {@code Marshaller}, and allow for features such as indentation. 
* @param properties the properties 
* @see javax.xml.bind.Marshaller#setProperty(String, Object) 
* @see javax.xml.bind.Marshaller#JAXB_ENCODING 
* @see javax.xml.bind.Marshaller#JAXB_FORMATTED_OUTPUT 
* @see javax.xml.bind.Marshaller#JAXB_NO_NAMESPACE_SCHEMA_LOCATION 
* @see javax.xml.bind.Marshaller#JAXB_SCHEMA_LOCATION 
*/ 
public void setMarshallerProperties(Map<String, ?> properties) { 
    this.marshallerProperties = properties; 
} 

2) Ich habe auch versucht die Unmarshaller im Code zu konfigurieren:

try { 
    jc = JAXBContext.newInstance("com.mycompany.mypkg"); 

    Unmarshaller u = jc.createUnmarshaller(); 
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
    dbf.setNamespaceAware(false);//Tried this option. 

    DocumentBuilder db = dbf.newDocumentBuilder(); 
    Document doc = db.parse(xmlFile.toFile()); 
    u.unmarshal(new DOMSource(doc)); 
    return (Foo)u.unmarshal(new StreamSource(xmlFile.toFile())); 
} catch (ParserConfigurationException | SAXException | IOException | JAXBException e) { 
    LOGGER.error("Erreur Unmarshalling CPL"); 
} 

3) Verschiedene Form mit einem SAXParser:

try { 
    jc = JAXBContext.newInstance("com.mycompany.mypkg"); 
    Unmarshaller um = jc.createUnmarshaller(); 
    final SAXParserFactory sax = SAXParserFactory.newInstance(); 
    sax.setNamespaceAware(false); 
    final XMLReader reader = sax.newSAXParser().getXMLReader(); 
    final Source er = new SAXSource(reader, new InputSource(new FileReader(xmlFile.toFile()))); 
    return (Foo)um.unmarshal(er); 
}catch(...) {[...]} 

Dieser funktioniert! Aber trotzdem würde ich lieber den Unmarshaller autowire machen können, ohne dieses hässliche conf jedes Mal zu benötigen.

Antwort

1

Namesapce Awareness ist Feature des Dokuments Reader/Builder/Parser nicht Marshallers. XML-Elemente aus verschiedenen Namespaces stellen unterschiedliche Entitäten == Objekte dar, sodass Marshaller sie nicht ignorieren können.

Sie haben die Namespaces in Ihrem SAX-Leser korrekt ausgeschaltet und wie Sie gesagt haben, hat es funktioniert. Ich verstehe Ihr Problem damit nicht, Ihr Marshaller kann immer noch injiziert werden, der Unterschied besteht darin, die Eingabedaten zu erhalten.

Der gleiche Trick mit Document Builder sollte auch funktionieren (ich werde es später testen), ich vermute, dass Sie immer noch den Marshaller mit "Hardcoded" Namespace, aber Ihr Dokument war Namespace frei.

In meinem Projekt verwende ich XSLT, um ähnliches Problem zu lösen. Namespace Awareness ist definitiv eine einfachere Lösung. Aber mit XSLT konnte ich nur einige Namespaces entfernen und auch meine Eingabe XML sind nicht immer identisch (Ignorieren von Namespaces) und manchmal muss ich einige Elemente umbenennen, so dass XSLT mir diese zusätzliche Flexibilität gibt.

Um Namespace entfernen Sie können solche Xslt Vorlage verwenden:

<xsl:stylesheet version="1.0" xmlns:e="http://timet.dom.robust.ed" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<xsl:template match="/"> 
    <xsl:copy> 
     <xsl:apply-templates /> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="*"> 
    <xsl:element name="{local-name()}"> 
     <xsl:apply-templates select="@* | node()" /> 
    </xsl:element> 
</xsl:template> 

<xsl:template match="@*"> 
    <xsl:attribute name="{local-name()}"> 
     <xsl:value-of select="."/> 
    </xsl:attribute> 
</xsl:template> 

<xsl:template match="text() | processing-instruction() | comment()"> 
    <xsl:copy /> 
</xsl:template> 
</xsl:stylesheet> 

dann in Java vor unmarshalling ich die Eingangsdaten umwandeln:

Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource); 
Source source = new DOMSource(xml); 
DOMResult result = new DOMResult(); 
transformer.transform(source, result); 
Verwandte Themen