前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dom4j解析带有命名空间的XML文件

Dom4j解析带有命名空间的XML文件

作者头像
卡尔曼和玻尔兹曼谁曼
发布2019-01-25 15:16:55
2.1K0
发布2019-01-25 15:16:55
举报

    今天我在解析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的入门方法,这里不再叙述。

    运行结果如下:

    长安大学渭水校区

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014年04月06日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档