【问题标题】:How to make JAXB unmarshaller to ignore prefixes?如何使 JAXB 解组器忽略前缀?
【发布时间】:2012-08-15 11:21:11
【问题描述】:

我有以下 XML:

<ns2:Person name="John" age="20" />

我想将它解组为从 XSD 生成的 JAXB 对象 Person。

这是我正在运行的代码:

JAXBContext context = JAXBContext.newInstance(PersoEntity.class);
Unmarshaller um = context.createUnmarshaller();
StringReader sr = new StringReader(xml);
Person p = (Person)um.unmarshal(sr);

令人惊讶的是,我得到了以下异常:

javax.xml.bind.UnmarshalException
 - with linked exception:
[org.xml.sax.SAXParseException: The prefix "ns2" for element "ns2:Person" is not bound.]

我该如何解决?谢谢

【问题讨论】:

  • 您只发布了一个 xml 标签...这真的是您的情况吗,即您只想解组这个片段(或者有一个完整的 xml 文档,应该定义 xmlns:ns2)?跨度>
  • 你猜对了,只有这一段是我想要的

标签: namespaces jaxb prefix unmarshalling


【解决方案1】:

获取片段

您当前获取 XML 片段的方式导致名称空间声明丢失。在您的片段中,ns2 不再是前缀,您只有一个带有冒号的元素名称(ns2:Person)。这将导致命名空间感知解析器出现问题。下面的文章可能是您获取 XML 片段的更好方法:

处理您的用例

使用您拥有的 XML 片段,您可以创建一个从 XML 元素中删除前缀的 XMLFilter,然后利用 JAXB 的 UnmarshallerHandler 进行解组。

演示

package forum11968399;

import java.io.StringReader;
import javax.xml.bind.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.XMLFilterImpl;

public class Demo {

    private static final String xml = "<ns2:Person name='John' age='20' />";

    public static void main(String[] args) throws Exception {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sp = spf.newSAXParser();
        XMLReader xmlReader = sp.getXMLReader();
        XMLFilter xmlFilter = new MyXMLFilter(xmlReader);

        JAXBContext context = JAXBContext.newInstance(PersonEntity.class);
        Unmarshaller um = context.createUnmarshaller();
        UnmarshallerHandler unmarshallerHandler = um.getUnmarshallerHandler();
        xmlFilter.setContentHandler(unmarshallerHandler);

        StringReader sr = new StringReader(xml);
        xmlFilter.parse(new InputSource(sr));
        PersonEntity p = (PersonEntity) unmarshallerHandler.getResult();
    }

    private static class MyXMLFilter extends XMLFilterImpl {

        public MyXMLFilter(XMLReader xmlReader) {
            super(xmlReader);
        }

        @Override
        public void startElement(String uri, String localName, String qName,
                Attributes attributes) throws SAXException {
            int colonIndex = qName.indexOf(':');
            if(colonIndex >= 0) {
                qName = qName.substring(colonIndex + 1);
            }
uri = XML_NAMESPACE; //to prevent unknown XML element exception, we have to specify the namespace here
            super.startElement(uri, localName, qName, attributes);
        }

        @Override
        public void endElement(String uri, String localName, String qName)
                throws SAXException {
            int colonIndex = qName.indexOf(':');
            if(colonIndex >= 0) {
                qName = qName.substring(colonIndex + 1);
            }
            super.endElement(uri, localName, qName);
        }

    }

}

PersonEntity

package forum11968399;

import javax.xml.bind.annotation.*;

@XmlRootElement(name="Person")
@XmlAccessorType(XmlAccessType.FIELD)
public class PersonEntity {

    @XmlAttribute
    private String name;

    @XmlAttribute
    private int age;

}

【讨论】:

  • 您的解决方案几乎奏效了。我不得不对其进行一些修改。即使我们去掉了前缀,由于命名空间问题,我仍然遇到了未知 XML 元素的异常。所以我只是将命名空间放在 Uri 变量中,它就起作用了 :)
【解决方案2】:

您最好的选择可能是将所需元素嵌套在另一个绑定命名空间的元素中。将它绑定到什么并不重要,只需将其设为可解析的有效 XML 文档即可。那你可以unmarshal by declared type

JAXBContext context = JAXBContext.newInstance(Person.class);
Unmarshaller um = context.createUnmarshaller();
String xml = "<ns2:Person name=\"John\" age=\"20\" />";
String xmlWithPrefixMapped = "<ns2:FakeElement xmlns:ns2=\"someuri\">" + xml + "</ns2:FakeElement>";
StringReader sr = new StringReader(xmlWithPrefixMapped);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(sr));
Node n = (Node) doc.getDocumentElement().getFirstChild();
JAXBElement<Person> personElement = um.unmarshal(n, Person.class);
Person p = personElement.getValue();

【讨论】:

  • 我得到以下信息:Unmarshaller 类型中的方法 unmarshal(Node, Class) 不适用于参数 (Element, Class)
  • 这对我有用,虽然我没有将它嵌套在新元素中,而是将命名空间信息添加到我得到的顶级标签中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-06
  • 2013-10-24
相关资源
最近更新 更多