使用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,多麼簡潔和高效。



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