簡體   English   中英

Jaxb忽略了解組時的命名空間

[英]Jaxb ignore the namespace on unmarshalling

我使用Jaxb2和Spring。 我正在嘗試解組由我的兩個客戶發送的一些XML。

到目前為止,我只需要處理一個發送了一些像這樣的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>

顯然,unmarshaller無法解組,因為它需要一些{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)我還嘗試在代碼中配置unmarshaller:

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,而不必每次都需要這種丑陋的conf。

Namesapce感知是文檔閱讀器/構建器/解析器的特征,而不是編組器。 來自不同命名空間的XML元素表示不同的實體==對象,因此編組者不能忽略它們。

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

與文檔構建器相同的技巧也應該工作(稍后我將對其進行測試),我懷疑你仍然使用帶有“硬編碼”命名空間的編組器但是你的文檔沒有命名空間。

在我的項目中,我使用XSLT來解決類似的問題。 設置名稱空間awarness絕對是更容易解決方案。 但是,使用XSLT,我可以選擇僅刪除一些名稱空間,而且我的輸入xml並不總是相同(忽略名稱空間),有時我必須重命名少數元素,因此XSLT給了我額外的靈活性。

要刪除名稱空間,您可以使用此類xslt模板:

<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中我轉換輸入數據:

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

謝謝大家,在這里分享了我的解決方案,它適用於我的代碼,我嘗試使它通用每個命名空間都包含“:”我編寫代碼如果任何標簽有“:”它將從xml中刪除,這用於在解組時跳過命名空間使用jaxb。

public class NamespaceFilter {

private NamespaceFilter() {

}

private static final String COLON = ":";

public static XMLReader nameSpaceFilter() throws SAXException {
    XMLReader xr = new XMLFilterImpl(XMLReaderFactory.createXMLReader()) {
        private boolean skipNamespace;

        @Override
        public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
            if (qName.indexOf(COLON) > -1) {
                skipNamespace = true;
            } else {
                skipNamespace = false;
                super.startElement("", localName, qName, atts);
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if (qName.indexOf(COLON) > -1) {
                skipNamespace = true;
            } else {
                skipNamespace = false;
                super.endElement("", localName, qName);
            }
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            if (!skipNamespace) {
                super.characters(ch, start, length);
            }
        }
    };
    return xr;
}

}

用於解組

XMLReader xr = NamespaceFilter.nameSpaceFilter();
Source src = new SAXSource(xr, new InputSource("C:\\Users\\binal\\Desktop\\response.xml"));
StringWriter sw = new StringWriter();
Result res = new StreamResult(sw);
TransformerFactory.newInstance().newTransformer().transform(src, res);
JAXBContext jc = JAXBContext.newInstance(Tab.class);
Unmarshaller u = jc.createUnmarshaller();
String done = sw.getBuffer().toString();
StringReader reader = new StringReader(done);
Tab tab = (Tab) u.unmarshal(reader);

System.out.println(tab);

`

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM