2015-04-14 104 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中解组我将输入数据之前