1、XPath 介绍
结构化查询语言(SQL)是一种针对查询特定类型的关系库而设计和优化的语言。和SQL相同,XPath也是一种查询语言,它一种为查询 XML 文档而设计的查询语言。下面这个简单的 XPath 查询可以在文档中找到作者为 conio 的所有图书的标题:
1 |
//book[author="conio"]/title |
作为对照,我们以一个java的纯DOM搜索代码来实现上面的功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
ArrayList result = new ArrayList(); NodeList books = doc.getElementsByTagName("book"); for (int i = 0; i < books.getLength(); i++) { Element book = (Element) books.item(i); NodeList authors = book.getElementsByTagName("author"); boolean isConio = false; for (int j = 0; j < authors.getLength(); j++) { Element author = (Element) authors.item(j); NodeList children = author.getChildNodes(); StringBuffer sb = new StringBuffer(); for (int k = 0; k < children.getLength(); k++) { Node child = children.item(k); // really should to do this recursively if (child.getNodeType() == Node.TEXT_NODE) { sb.append(child.getNodeValue()); } } if (sb.toString().equals("conio")) { isConio = true; break; } } if (isConio) { NodeList titles = book.getElementsByTagName("title"); for (int j = 0; j < titles.getLength(); j++) { result.add(titles.item(j)); } } } |
xpath语法结构如下:
2、Java 代码编程示例
Java 5 推出了 javax.xml.xpath
包,提供一个引擎和对象模型独立的 XPath 库。这个包也可用于 Java 1.3 及以后的版本,但需要单独安装 Java API for XML Processing (JAXP) 1.3。
xml 文档:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<inventory> <book year="2000"> <title>Snow Crash</title> <author>conio</author> <publisher>Spectra</publisher> <isbn>0553380958</isbn> <price>14.95</price> </book> <book year="2005"> <title>Burning Tower</title> <author>Larry Niven</author> <author>Jerry Pournelle</author> <publisher>Pocket</publisher> <isbn>0743416910</isbn> <price>5.99</price> <book> <book year="1995"> <title>Zodiac</title> <author>conio<author> <publisher>Spectra</publisher> <isbn>0553573862</isbn> <price>7.50</price> <book> <!-- more books... --> </inventory> |
XPath查询语法:
- 查找所有图书的 XPath 查询:
//book[author="conio"]
- 找出这些图书的标题,只要增加一步:
//book[author="conio"]/title
- 找出标题的内容:
//book[author="conio"]/title/text()
用XPath查询的代码完整示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import java.io.IOException; import org.w3c.dom.*; import org.xml.sax.SAXException; import javax.xml.parsers.*; import javax.xml.xpath.*; public class XPathExample { public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, XPathExpressionException { DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); domFactory.setNamespaceAware(true); // never forget this! DocumentBuilder builder = domFactory.newDocumentBuilder(); Document doc = builder.parse("books.xml"); XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); XPathExpression expr = xpath.compile("//book[author='conio']/title/text()"); Object result = expr.evaluate(doc, XPathConstants.NODESET); NodeList nodes = (NodeList) result; for (int i = 0; i < nodes.getLength(); i++) { System.out.println(nodes.item(i).getNodeValue()); } } } |
3、Android里面从String.xml里面查找某个字符串key对应的value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/** * Finds key in strings.xml file and returns text value * * @param directory Root directory of apk * @param key String reference (ie @string/foo) * @return String|null * @throws AndrolibException */ public static String pullValueFromStrings(File directory, String key) throws AndrolibException { if (key == null || ! key.contains("@")) { return null; } File file = new File(directory, "/res/values/strings.xml"); key = key.replace("@string/", ""); if (file.exists()) { try { Document doc = loadDocument(file); XPath xPath = XPathFactory.newInstance().newXPath(); XPathExpression expression = xPath.compile("/resources/string[@name=" + '"' + key + "\"]/text()"); Object result = expression.evaluate(doc, XPathConstants.STRING); if (result != null) { return (String) result; } } catch (SAXException | ParserConfigurationException | IOException | XPathExpressionException ignored) { } } return null; } |
4、Android 读取manifest里面的属性值
例如获取application的name值:
这里需要注意如果/manifest/application/@android:name 是找不到的,因为没有设置命名空间。换成命名空间的写法为:
1 |
//*[local-name()='application']/@name |
1 2 3 4 |
XPath xPath = XPathFactory.newInstance().newXPath(); XPathExpression expression = xPath.compile("/manifest/application/@name"); manifestDoc = DomUtil.readFrom(Packer.getInstance().getPackPathManager().getApkManifestPath()); String value = String.valueOf(expression.evaluate(manifestDoc, XPathConstants.STRING)); |