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