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,多么简洁和高效。