【问题标题】:JAXB - convert XML file with XSD/namespace references in itJAXB - 转换其中包含 XSD/命名空间引用的 XML 文件
【发布时间】:2019-07-16 14:49:34
【问题描述】:

如何将带有 XSD/命名空间的 XML 转换为对象?

我得到这个错误:

javax.xml.bind.UnmarshalException:意外元素 (uri:“http://www.opengis.net/wfs/2.0”,本地:“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 字符串转换为对象?

【问题讨论】:

    标签: java jaxb


    【解决方案1】:

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

    • 转换器类
    • 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());
        }
    }
    

    【讨论】:

    • 不错!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-09
    • 2016-09-21
    相关资源
    最近更新 更多