为了账号安全,请及时绑定邮箱和手机立即绑定

JAXB - 转换其中包含 XSD/命名空间引用的 XML 文件

JAXB - 转换其中包含 XSD/命名空间引用的 XML 文件

饮歌长啸 2023-03-31 14:46:45
如何将带有 XSD/命名空间的 XML 转换为对象?我收到此错误:javax.xml.bind.UnmarshalException:意外元素(uri:“ http://www.opengis.net/wfs/2.0 ”,本地:“FeatureCollection”)。预期的元素是 <{}FeatureCollection>这是示例 XML:<wfs:FeatureCollection xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" numberMatched="7961422" numberReturned="0" timeStamp="2019-07-16T09:44:51.540Z" xsi:schemaLocation="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd"/>我的简单 JAXB 转换器是:public static Object convertXmlToObject(String xmlString, Class targetClass) {    JAXBContext jaxbContext;    try {        jaxbContext = JAXBContext.newInstance( targetClass);        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();        return jaxbUnmarshaller.unmarshal(new StringReader(xmlString));    } catch (JAXBException e) {        e.printStackTrace();        return null;    }}这个方法的调用是:TargetObject to = (TargetObject) converter.convertXmlToObject( xmlString, TargetObject.class);目标对象是:@XmlRootElement( name="FeatureCollection")public class TargetObject {    private long numberMatched = -1;    private long numberReturned = -1;    private LocalDateTime timeStamp;    // ... all getters    @XmlAttribute    public void setNumberMatched(long numberMatched) {        this.numberMatched = numberMatched;    }    @XmlAttribute    public void setNumberReturned(long numberReturned) {        this.numberReturned = numberReturned;    }    @XmlAttribute    @XmlJavaTypeAdapter(value = LocalDateTimeAdapter.class)    public void setTimeStamp(LocalDateTime timeStamp) {        this.timeStamp = timeStamp;    }}如何改进我的代码以将 XML 字符串转换为对象?
查看完整描述

1 回答

?
扬帆大鱼

TA贡献1799条经验 获得超9个赞

享受这个通用的解决方案:

  • 转换器类

  • Junit 测试——显示了 1 个没有名称空间的测试,但它确实适用于名称空间

使用 XSLT 剥离名称空间的转换器类。JAXB 有时过于直白,您可以在许多帖子中看到这一点。

public class XmlToPojo {

    public static Object convertXmlToObject(String xmlString, Class targetClass) {

        JAXBContext jaxbContext;

        try {

            // Step 1 - remove namespaces

            StreamSource xmlSource = new StreamSource(new StringReader(xmlString));

            StreamResult result = new StreamResult(new StringWriter());

            removeNamespace(xmlSource, result);

            // Step 2 - convert XML to object

            jaxbContext = JAXBContext.newInstance(targetClass);

            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();

            return jaxbUnmarshaller.unmarshal(new StringReader(result.getWriter().toString()));

        } catch (Exception e) {

            e.printStackTrace();

            return null;

        }

    }


    // Remove namespaces from XML


    private static String xsltNameSpaceRemover = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +

            "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n" +

            "\n" +

            "    <xsl:output indent=\"yes\" method=\"xml\" encoding=\"utf-8\" omit-xml-declaration=\"yes\"/>\n" +

            "\n" +

            "    <!-- Stylesheet to remove all namespaces from a document -->\n" +

            "    <!-- NOTE: this will lead to attribute name clash, if an element contains\n" +

            "        two attributes with same local name but different namespace prefix -->\n" +

            "    <!-- Nodes that cannot have a namespace are copied as such -->\n" +

            "\n" +

            "    <!-- template to copy elements -->\n" +

            "    <xsl:template match=\"*\">\n" +

            "        <xsl:element name=\"{local-name()}\">\n" +

            "            <xsl:apply-templates select=\"@* | node()\"/>\n" +

            "        </xsl:element>\n" +

            "    </xsl:template>\n" +

            "\n" +

            "    <!-- template to copy attributes -->\n" +

            "    <xsl:template match=\"@*\">\n" +

            "        <xsl:attribute name=\"{local-name()}\">\n" +

            "            <xsl:value-of select=\".\"/>\n" +

            "        </xsl:attribute>\n" +

            "    </xsl:template>\n" +

            "\n" +

            "    <!-- template to copy the rest of the nodes -->\n" +

            "    <xsl:template match=\"comment() | text() | processing-instruction()\">\n" +

            "        <xsl:copy/>\n" +

            "    </xsl:template>\n" +

            "\n" +

            "</xsl:stylesheet>";


    private static void removeNamespace(Source xmlSource, Result xmlOutput) throws TransformerException {

        TransformerFactory factory = TransformerFactory.newInstance();

        StreamSource xsltSource = new StreamSource(new StringReader(xsltNameSpaceRemover));

        Transformer transformer = factory.newTransformer(xsltSource);

        transformer.transform(xmlSource, xmlOutput);

    }

}

一个简单的 Junit 测试:


public class XmlToPojoTest {

    @Test

    public void testBasic() {

        String xmlString = "<employee>" +

                "    <department>" +

                "        <id>101</id>" +

                "        <name>IT-ABC</name>" +

                "    </department>" +

                "    <firstName>JJ</firstName>" +

                "    <id>1</id>" +

                "    <lastName>JoHo</lastName>" +

                "</employee>";

        XmlToPojo xmlToPojo = new XmlToPojo();

        Employee emp = (Employee) xmlToPojo.convertXmlToObject(xmlString, Employee.class);

        assertEquals("JJ", emp.getFirstName());

        assertEquals("IT-ABC", emp.getDepartment().getName());

    }

}


查看完整回答
反对 回复 2023-03-31
  • 1 回答
  • 0 关注
  • 148 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信