使用dom4j读取XML数据

在数据处理过程中,遇到xml格式的数据含有大量的标签、属性等信息。在java中,使用dom4j读取时,会遇到各种复杂的情况。

static String rawXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ROWDATA>    <ROW>        <EMPNO>7499</EMPNO>        <ENAME firstname=\"zhang\" lastname=\"shanfeng\">ALLEN</ENAME>        <JOB type=\"basic\">SALESMAN</JOB>        <MGR>7698</MGR>        <HIREDATE>1981-2-20</HIREDATE>        <SAL>3200.0</SAL>        <COMM>300.00</COMM>        <DEPTNO>30</DEPTNO>    </ROW>    <ROW>        <EMPNO>7566</EMPNO>        <ENAME>JONES</ENAME>        <JOB>MANAGER</JOB>        <MGR>7839</MGR>        <HIREDATE>1981-4-2</HIREDATE>        <SAL>5950.0</SAL>        <COMM />        <DEPTNO>20</DEPTNO>    </ROW>    </ROWDATA>";

这个字符串就是典型的XML格式的数据,我们使用XPath可以快速读取到需要的数据。

    public static void readElement() throws Exception {

        Document doc = DocumentHelper.parseText(rawXML);
        List list = doc.selectNodes("ROWDATA/ROW/EMPNO");
        for (Object obj : list) {
            Element el = (Element) obj;
            System.out.println(el.getText());
        }
    }

    但是,如果xml数据中有xmlns属性的话,就是命名空间,那么这种XPath写法将失效。
    
    static String rawXML2 = "<Property xmlns=\"http://www.opentravel.org/OTA/2003/05\" BrandCode=\"50\" HotelCode=\"214200\" HotelCityCode=\"2\" HotelName=\"锦江之星(上海场中路店)\" AreaID=\"117\"><VendorMessages><VendorMessage InfoType=\"23\"><SubSection><Paragraph><Text>http://Images4.c-ctrip.com/target/hotel/215000/214200/b812664399894844b77d91fe885a0994_100_75.jpg</Text></Paragraph></SubSection></VendorMessage></VendorMessages><Position Latitude=\"31.30221\" Longitude=\"121.41662\"/><Address><AddressLine>洛场路118号</AddressLine><CityName>上海</CityName><PostalCode>200436</PostalCode></Address></Property>";

    
    接下来,我花费几乎一天的时间,来分析解决这个问题。对XML语法不熟悉,对XPath不熟悉,甚至开始时都不知道它是一种XML操作语言语法,就是现在也不太清楚,对于dom4j也同样不熟悉。整个过程可谓是费尽周折。
    
    我写了一个新方法,用于解析带有namespace的XML数据。
    
    List list =el2.selectNodes("/Property/VendorMessages/VendorMessage/SubSection/Paragraph/Text");
    直接操作,得到null值。
    
    想到两种解决方法。其一,是将源数据中namespace信息去掉。其二,是使用dom4j合理地读取到数据。
    
    在第一种方法中,我使用remove属性(attribute),remove命名空间(namespace),怎么也不能去掉。然后使用一种更粗暴的方法,直接replaceAll所有的xmlns=开头的字符串。
    rawXML2=rawXML2.replaceAll("xmlns=\"[^\"]*\"","");
    这个虽然管用,但太粗暴了。
    
    在第二种方法中,我使用XPath的语法读取到几层节点下的数据。
    Node node = el2.selectSingleNode("/*[local-name()='Property']/*[local-name()='VendorMessages']/*[local-name()='VendorMessage']/*[local-name()='SubSection']/*[local-name()='Paragraph']/*[local-name()='Text']");
    
    这个local-name我是初次使用,完全不理解的它的用处。
    
    下面是方法的实现代码    
    
    public static void readElementWithNS() throws Exception {

        // rawXML2=rawXML2.replaceAll("xmlns=\"[^\"]*\"","");

        Document doc = DocumentHelper.parseText(rawXML2);

        Element el2 = (Element) doc.getRootElement();

        // List list =el2.selectNodes("/Property/VendorMessages/VendorMessage/SubSection/Paragraph/Text");

        Node node = el2.selectSingleNode("/*[local-name()='Property']/*[local-name()='VendorMessages']/*[local-name()='VendorMessage']/*[local-name()='SubSection']/*[local-name()='Paragraph']/*[local-name()='Text']");

        Element el3 = (Element) node;

        String logoURL = el3.getText();
        System.out.println("logoURL:" + logoURL);
        
    }
    
    
    因为XML文件足够复杂,我写了独立的方法,来处理。
    
    public static void readElementWithNS2() throws Exception {
        Document doc = DocumentHelper.parseText("<root>"+rawXML2+"</root>");
        Element el2 = (Element) doc.getRootElement();
        treeNodes(el2);
    }
    

    public static void treeNodes(Element element) throws DocumentException {
        for (int i = 0, size = element.nodeCount(); i < size; i++) {
            Node node = element.node(i);
            if (node instanceof Element) {

                if (node.getName().equals("Property")) {

                    // System.out.println("Property:" + node.asXML());

                    /*
                     * String
                     * xml=node.asXML().replaceAll("xmlns=\"[^\"]*\"","");
                     * Document doc=DocumentHelper.parseText(xml); Element
                     * el=doc.getRootElement();
                     */

                    Element el = (Element) node;

                    String HotelCode = el.attributeValue("HotelCode");
                    String HotelName = el.attributeValue("HotelName");
                    String AreaID = el.attributeValue("AreaID");
                    String BrandCode = el.attributeValue("BrandCode");

                    String logoURL = "";

                    String Latitude = "";
                    String Longitude = "";

                    String AddressLine = "";
                    String CityName = "";
                    String PostalCode = "";

                    String xPathString = "//*[local-name()='Property' and namespace-uri()='http://www.opentravel.org/OTA/2003/05']/*[local-name()='VendorMessages']/*[local-name()='VendorMessage']/*[local-name()='SubSection']/*[local-name()='Paragraph']/*[local-name()='Text']";
                    Node node2 = el.selectSingleNode(xPathString);
                    Element el2 = (Element) node2;
                    logoURL = el2.getText();

                    xPathString = "//*[local-name()='Property' and namespace-uri()='http://www.opentravel.org/OTA/2003/05']/*[local-name()='Position']";
                    node2 = el.selectSingleNode(xPathString);
                    el2 = (Element) node2;

                    Latitude = el2.attributeValue("Latitude");
                    Longitude = el2.attributeValue("Longitude");

                    xPathString = "//*[local-name()='Property']/*[local-name()='Address']";

                    List list = el.selectNodes(xPathString);

                    for (Object obj : list) {
                        Element addr = (Element) obj;
                        AddressLine = (addr.element("AddressLine"))    .getTextTrim();
                        CityName = (addr.element("CityName")).getTextTrim();
                        PostalCode = (addr.element("PostalCode")).getTextTrim();
                        }

                    System.out.println(HotelCode + ":" + HotelName + ":"
                            + AreaID + ":" + BrandCode + ":" + logoURL + ":"
                            + Latitude + ":" + Longitude + ":" + AddressLine
                            + ":" + CityName + ":" + PostalCode + ";");
                }
                else {
                    treeNodes((Element) node);
                }

            }
        }
    }



顺便说一句,非常痛恨XML,为什么不用json,多么简洁和高效。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章