Jaxb在解组时忽略名称空间 [英] Jaxb ignore the namespace on unmarshalling

查看:73
本文介绍了Jaxb在解组时忽略名称空间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Jaxb2和Spring.我正试图解组由2个客户发送的一些XML.

I use Jaxb2 and Spring. I am trying to unmarshal some XML that are sent by 2 of my customers.

到目前为止,我只需要处理一个发送这样的xml的客户:

Up to now, I only had to handle one customer which sent some xml like this :

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

这样绑定到POJO:

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

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

  [...]
}

我发现以前的开发人员在解组器中对名称空间进行了硬编码,以使其起作用.

I discovered that the previous developer hardcoded the namespace in the unmarshaller in order to make it work.

现在,第二个客户发送相同的XML,但是更改了名称空间!

Now, the second customer sends the same XML but changes the namespace!

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

很明显,解组器无法解组,因为它期望某些{com.acme}foo而不是{com.xyz}foo.不幸的是,不能要求客户更改XML.

Obviously, the unmarshaller fails to unmarshall because it expects some {com.acme}foo instead of {com.xyz}foo. Unforunately, asking the customer to change the XML is not an option.

我尝试过的事情:

1)application-context.xml中,我搜索了一种配置,该配置使我可以忽略命名空间,但找不到一个:

1) In application-context.xml, I searched for a configuration which would allow me to ignore the namespace but could not find one :

<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中列出的选项:

it seems that the only available options are the ones listed in the Jaxb2Marshaller's 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),我还尝试在代码中配置反编组器:

2) I also tried to configure the unmarshaller in the code :

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的不同形式:

3) Different form with a 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,而不必每次都需要这个丑陋的conf.

This one works! But still, I would prefer to be able to autowire the Unmarshaller without needing this ugly conf everytime.

推荐答案

名称空间意识是文档读取器/生成器/解析器(而非编组器)的功能.来自不同名称空间的XML元素表示不同的实体==对象,因此编组人员无法忽略它们.

Namesapce awareness is feature of the document reader/builder/parser not marshallers. XML elements from different namespaces represents different entities == objects, so marshallers cannot ignore them.

您已经正确关闭了SAX阅读器中的名称空间,并且正如您所说的那样起作用.我不了解您的问题,仍然可以注入您的编组,区别在于获取输入数据.

You correctly switched off the namespaces in your SAX reader and as you said it worked. I don't understand your problem with it, your marshaller still can be injected, the difference is in obtaining the input data.

与文档生成器相同的技巧也应该起作用(稍后将对其进行测试),我怀疑您仍在使用具有硬编码"名称空间的编组器,但文档中没有名称空间.

The same trick with document builder should also work (I will test it later on), I suspect that you were still using the marshaller with "hardcoded" namespace but your document was namespace free.

在我的项目中,我使用XSLT解决类似的问题.设置名称空间警戒绝对是更简单的解决方案.但是,使用XSLT可以选择性地仅删除一些名称空间,而且我的输入xml并不总是相同的(忽略名称空间),有时我必须重命名一些元素,因此XSLT为我提供了额外的灵活性.

In my project I use XSLT to solve similar issue. Setting namespace awarness is definitely easier solution. But, with XSLT I could selectviely remove only some namespaces and also my my input xml are not always identical (ignoring namespaces) and sometimes I have to rename few elements so XSLT gives me this extra flexibility.

要删除名称空间,可以使用以下xslt模板:

To remove namespaces you can use such xslt template:

<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中进行解组之前,我先转换输入数据:

Then in Java before unmarshalling I transform the input data:

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

这篇关于Jaxb在解组时忽略名称空间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆