首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Jaxb在解组时忽略名称空间

Jaxb在解组时忽略名称空间
EN

Stack Overflow用户
提问于 2015-04-14 08:44:12
回答 3查看 17K关注 0票数 11

我使用Jaxb2和Spring。我正在尝试解压缩由我的两个客户发送的一些XML。

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

代码语言:javascript
复制
<foo xmlns="com.acme">
  <bar>[...]</bar>
<foo>

它绑定到这样的POJO上:

代码语言:javascript
复制
@XmlType(name = "", propOrder = {"bar"})
@XmlRootElement(name = "Foo")
public class Foo {

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

  [...]
}

我发现前面的开发人员在解编组器中硬编码了名称空间,以便使其工作。

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

代码语言:javascript
复制
<foo xmlns="com.xyz">
  <bar>[...]</bar>
<foo>

显然,解除封送处理程序无法解锁,因为它期望一些{com.acme}foo而不是{com.xyz}foo。不幸的是,要求客户更改XML并不是一种选择。

我尝试了什么:

1) In application-context.xml,我搜索允许忽略命名空间但却找不到名称空间的配置:

代码语言:javascript
复制
<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中列出的选项:

代码语言:javascript
复制
/**
 * 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) I还试图在代码中配置解封组程序:

代码语言:javascript
复制
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的不同形式的

代码语言:javascript
复制
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(...) {[...]}

这个可以工作!但是,我还是希望能够自动解封解封器,而不用每次都用这个难看的房间。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-04-14 12:27:18

Namesapce感知是文档读取器/构建器/解析器的特性,而不是封送器。来自不同名称空间的XML元素表示不同的实体==对象,因此封送器不能忽略它们。

您正确地关闭了SAX读取器中的命名空间,就像您说的那样,它起了作用。我不明白您的问题所在,您的封送器仍然可以被注入,区别在于获取输入数据。

使用document的同样技巧也应该有效(稍后我将对其进行测试),我怀疑您仍然使用带有“硬编码”命名空间的封送器,但是您的文档没有命名空间。

在我的项目中,我使用XSLT来解决类似的问题。设置命名空间感知肯定更容易解决方案。但是,使用XSLT,我可以选择性地删除一些名称空间,而且我的输入xml并不总是相同的(忽略名称空间),有时我不得不重命名几个元素,因此XSLT给了我额外的灵活性。

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

代码语言:javascript
复制
<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中,在解组之前,我转换输入数据:

代码语言:javascript
复制
Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);
Source source = new DOMSource(xml);
DOMResult result = new DOMResult();
transformer.transform(source, result);
票数 2
EN

Stack Overflow用户

发布于 2019-04-22 07:32:18

谢谢大家,这里分享了我的解决方案,这个解决方案适用于我的代码,我试着使它成为通用的每个名称空间包含:“如果有任何标记,我会编写代码":”它将从xml中删除,这用于在使用jaxb进行解组时跳过命名空间。

代码语言:javascript
复制
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;
}

}

解编组

代码语言:javascript
复制
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);

`

票数 1
EN

Stack Overflow用户

发布于 2022-04-20 06:29:37

我遵循Java文档来处理xml中的命名空间,在解组过程中,它做到了这一点。

代码语言:javascript
复制
   JAXBContext jc = JAXBContext.newInstance( "com.acme.foo" );
   Unmarshaller u = jc.createUnmarshaller();

   DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
   dbf.setNamespaceAware(false);
   DocumentBuilder db = dbf.newDocumentBuilder();
   Document doc = db.parse(new File( "nosferatu.xml"));
   //If just a string
   //InputSource is = new InputSource(new StringReader(line));
   //Document doc = db.parse(is)
   Object o = u.unmarshal( doc );

使用Java、JAXB上下文和解封送功能。https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/Unmarshaller.html

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29622877

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档