歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Dom4j解析帶有命名空間的XML文件

今天我在解析KML文件的過程中,使用XPath表達式,可是返回的結果總是null,糾結了很久,後來通過查資料,發現是我的KML中有命名空間的緣故。

首先,說明一些什麼是KML,因為下面的例子中會用到KML。KML是Keyhole Markup Language的縮寫,是一種基於XML 語法與格式的、用於描述和保存地理信息(如點、線、圖像、多邊形和模型等)的編碼規范,可以被 Google Earth 和 Google Maps 識別並顯示。Google Earth 和 Google Maps 處理 KML 文件的方式與網頁浏覽器處理 HTML 和 XML 文件的方式類似。Google Earth中通常使用KMZ文件,KMZ文件是壓縮過的KML文件。目前,KML 是由開放地理空間聯盟(Open Geospatial Consortium, Inc.,簡稱 OGC)維護的國際標准。

下面來看一個KML文件實例,即本文中要用到的XML文件:

(KML文件可以通過在Google Earth中得到,這裡我利用Google Earth搜索長安大學渭水校區,然後添加地標,將位置另存為KML文件)

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Document>
 <name>長安大學渭水校區</name>
 <Style id="s_ylw-pushpin_hl">
  <IconStyle>
   <scale>1.3</scale>
   <Icon>
    <href>http://maps.google.com/mapfiles/kml/pushpin/grn-pushpin.png</href>
   </Icon>
   <hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/>
  </IconStyle>
  <ListStyle>
  </ListStyle>
 </Style>
 <Style id="s_ylw-pushpin">
  <IconStyle>
   <scale>1.1</scale>
   <Icon>
    <href>http://maps.google.com/mapfiles/kml/pushpin/grn-pushpin.png</href>
   </Icon>
   <hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/>
  </IconStyle>
  <ListStyle>
  </ListStyle>
 </Style>
 <StyleMap id="m_ylw-pushpin">
  <Pair>
   <key>normal</key>
   <styleUrl>#s_ylw-pushpin</styleUrl>
  </Pair>
  <Pair>
   <key>highlight</key>
   <styleUrl>#s_ylw-pushpin_hl</styleUrl>
  </Pair>
 </StyleMap>
 <Placemark>
  <name>長安大學渭水校區</name>
  <LookAt>
   <longitude>108.9032130001538</longitude>
   <latitude>34.36892100035922</latitude>
   <altitude>0</altitude>
   <heading>8.682278169459107e-011</heading>
   <tilt>0</tilt>
   <range>999.7995012938454</range>
   <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>
  </LookAt>
  <styleUrl>#m_ylw-pushpin</styleUrl>
  <Point>
   <gx:drawOrder>1</gx:drawOrder>
   <coordinates>108.9032130001538,34.36892100035922,0</coordinates>
  </Point>
 </Placemark>
</Document>
</kml>

KML文件可以使用Google Earth打開,效果如下:

現在進入正題,我們可以看到上面的XML文件包含命名空間,如果我們任然使用以前沒有命名空間的方法用XPath獲取節點元素會出現什麼情況呢?

實例如下:

public class XMLReader {
 public static void main(String[] args) throws DocumentException {
  SAXReader reader = new SAXReader();
  Document document = reader.read(new File("長安大學渭水校區.kml"));
 
  Node name = document.selectSingleNode("//name");
  if (name == null) {
   System.out.println("name節點為null!");
  } else {
   System.out.println(name.getText());
  }
 }
}

運行結果如下:name節點為null!

可是我的name節點明明不為null呀,這都是命名空間惹的禍!

下面我們著重看看解決辦法:

方法一:設置你的xpath的命名空間setNamespaceURIs

實例如下:

public class KMLReader1 {

 public static void main(String[] args) throws DocumentException {
  SAXReader reader = new SAXReader();
  Document document = reader.read(new File("長安大學渭水校區.kml"));
 
  //方法一:設置你的xpath的命名空間setNamespaceURIs
  Map<String, String> xmlMap = new HashMap<>();
  xmlMap.put("default", "http://www.opengis.net/kml/2.2");
  XPath xPath = document.createXPath("//default:name");
  xPath.setNamespaceURIs(xmlMap);
  Node name = xPath.selectSingleNode(document);
  System.out.println(name.getText());
 
 }
}

首先,聲明一個Map對象,添加命名空間,Map的鍵為命名空間的名稱,這裡是默認命名空間所以這裡Map的鍵可以隨便取,我取名叫default,Map的值為命名空間的值,即http://www.opengis.net/kml/2.2。然後,聲明一個XPath對象,在createXPath方法中,要使用帶命名空間前綴的XPath表達式,即defau:name。最後,調用setNamespaceURIs方法,設置XPath的命名空間。

運行結果如下:

長安大學渭水校區

方法二:設置你的DocumentFactory()的命名空間 setXPathNamespaceURIs

實例如下:

public class KMLReader2 {

 public static void main(String[] args) throws DocumentException {
  //方法二:設置你的DocumentFactory()的命名空間 setXPathNamespaceURIs
  Map<String, String> xmlMap = new HashMap<>();
  xmlMap.put("default", "http://www.opengis.net/kml/2.2");
  xmlMap.put("gx", "http://www.google.com/kml/ext/2.2");
 
  SAXReader reader = new SAXReader();
  reader.getDocumentFactory().setXPathNamespaceURIs(xmlMap);
  Document document = reader.read(new File("長安大學渭水校區.kml"));
 
  Node name = document.selectSingleNode("//default:name");
  System.out.println(name.getText());
 
  Node altitudeMode = document.selectSingleNode("//gx:altitudeMode");
  System.out.println(altitudeMode.getText());
 }
}

這裡,我們設置的不是XPath的命名空間了,而是DocumentFactory的命名空間,其原理都差不多,只不過作用范圍不一樣,設置XPath的命名空間作用在XPath表達式,設置DocumentFactory作用在整個Document對象上。所以這裡不再啰嗦,和上面一樣。

運行結果如下:

長安大學渭水校區

relativeToSeaFloor

方法三:不使用開發環境給你提供的一系列對象,而是用XPath語法中自帶的local-name() 和 namespace-uri()指定你要使用的節點名和命名空間

實例如下:

public class KMLReader3 {

 public static void main(String[] args) throws DocumentException {
  // 不使用開發環境給你提供的一系列對象,而是用XPath語法中自帶的local-name() 和 namespace-uri()
  // 指定你要使用的節點名和命名空間
  SAXReader reader = new SAXReader();
  Document document = reader.read(new File("長安大學渭水校區.kml"));

  Node name = document
    .selectSingleNode("//*[local-name()='name' and namespace-uri()='http://www.opengis.net/kml/2.2']");
  System.out.println(name.getText());
 }
}

這裡直接在XPath表達式中指出命名空間,local-name()代表元素名稱,namespace-uri()代表元素所在命名空間。

運行結果如下:

長安大學渭水校區

方法四:不使用XPath表達式,直接用element的element方法取一個子元素或elementIterator方法取多個元素

實例如下:

public class KMLReader4 {

 public static void main(String[] args) throws DocumentException {
  //不使用XPath,直接用element的element方法取一個子元素或elementIterator方法取多個元素
  SAXReader reader = new SAXReader();
  Document document = reader.read(new File("長安大學渭水校區.kml"));
 
  Element root = document.getRootElement();
  Element name = root.element("Document").element("name");
  System.out.println(name.getText());
 }
}

這種方法是Dom4j的入門方法,這裡不再敘述。

運行結果如下:

長安大學渭水校區

Copyright © Linux教程網 All Rights Reserved