2015-04-14 145 views
6

我使用Jaxb2和Spring。我正試圖解組一些由我的客戶發送的XML。Jaxb忽略unmarshalling上的命名空間

到現在爲止,我只需要處理一個客戶它派了一些這樣的XML:

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

綁定到一個POJO是這樣的:

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

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

    [...] 
} 

我發現,以前的開發人員對unmarshaller中的命名空間進行了硬編碼,以使其工作。

現在,第二個客戶發送相同的XML但改變了命名空間!

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

顯然,解組未能解組,因爲它預計一些{com.acme}foo代替{com.xyz}foo。不幸的是,要求客戶更改XML不是一種選擇。

我的嘗試:

1)application-context.xml,我搜索的配置這將讓我忽略了命名空間,但找不到一個:

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

似乎唯一可用的選項是Jaxb2Marshaller的Javadoc中列出的選項:

/** 
* 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)我也試過配置解組代碼:

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)不同的形式創建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(...) {[...]} 

這一個工程!但是,我仍然希望能夠自動調用Unmarshaller,而不需要每次都需要這個難看的配置。

回答

1

Namesapce意識是文檔閱讀器/構建器/解析器不是marshallers的特性。來自不同名稱空間的XML元素表示不同的實體==對象,因此編組人員不能忽略它們。

您正確關閉了SAX閱讀器中的命名空間,正如您所說的那樣。我不明白你的問題,你的編組仍然可以注入,不同之處在於獲取輸入數據。

與文檔生成器相同的技巧也應該工作(我將在稍後對其進行測試),我懷疑你仍然在使用具有「硬編碼」命名空間的編組器,但是你的文檔是無名稱空間的。

在我的項目中,我使用XSLT來解決類似的問題。設置命名空間awarness絕對是更簡單的解決方案。但是,使用XSLT,我可以選擇只刪除一些名稱空間,而且我的輸入xml並不總是相同的(忽略名稱空間),有時我必須重命名少量元素,以便XSLT爲我提供這種額外的靈活性。

要刪除的命名空間,你可以使用這樣的XSLT模板:

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

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

然後在Java中解組我將輸入數據之前