XPath 在线测试器
针对 XML 测试 XPath 表达式,查看所有匹配节点
XML 输入
什么是 XPath?
XPath(XML 路径语言)是一种用于从 XML 文档中选取节点的查询语言。XPath 由 W3C 作为 XSLT 标准的一部分定义,将 XML 文档视为节点树,并提供基于路径的语法来导航该树。例如,XPath 表达式 //book[@category="fiction"]/title 会选取所有 category 属性值为 "fiction" 的 book 元素下的 title 子元素。XPath 1.0 是所有主流浏览器和大多数 XML 库所支持的版本,于 1999 年作为 W3C 推荐标准发布,至今仍是部署最广泛的版本。
XPath 表达式返回四种结果类型之一:节点集、字符串、数字或布尔值。节点集是最常见的结果类型,包含零个或多个 XML 节点(元素、属性、文本节点、注释或处理指令)。字符串、数字和布尔值结果来自 XPath 函数,例如 count()、sum()、contains() 以及布尔比较。这套类型系统使 XPath 既适合提取数据,也适合在 XSLT 样式表和 XML Schema 断言中编写条件逻辑。
XPath 1.0 表达式在各处均可使用:JavaScript 的 document.evaluate()、Python 的 lxml 和 ElementTree、Java 的 javax.xml.xpath、PHP 的 DOMXPath,以及命令行工具 xmllint。XPath 2.0 和 3.1 提供了更丰富的类型系统和函数,但需要专用引擎(如 Saxon)。默认使用 XPath 1.0 即可。只有在需要序列、正则表达式或高阶函数时,才考虑使用 2.0 或 3.1,并接受对 Saxon 或 BaseX 的依赖。
为什么使用在线 XPath 测试器?
编写正确的 XPath 表达式需要理解文档结构并针对真实数据进行测试。本工具提供交互式环境,让你可以反复调试表达式,无需搭建项目或编写样板代码。
XPath 测试器使用场景
XPath 轴参考
轴定义了相对于当前(上下文)节点的导航方向。完整语法为 axis::node-test[predicate],但大多数开发者日常使用的是缩写形式(//、@、..)。下表列出了 XPath 1.0 的所有轴及实用示例。
| 轴 | 示例 | 说明 |
|---|---|---|
| child | child::book | Direct children named "book" |
| descendant | descendant::title | All "title" elements at any depth |
| parent | parent::* | The parent of the current node |
| ancestor | ancestor::catalog | All ancestors named "catalog" |
| following-sibling | following-sibling::book | Siblings after the current node |
| preceding-sibling | preceding-sibling::book | Siblings before the current node |
| attribute | attribute::lang | The "lang" attribute of the node |
| self | self::book | The current node if it is "book" |
| descendant-or-self | //title | Shorthand: any "title" in the tree |
| ancestor-or-self | ancestor-or-self::* | Current node plus all ancestors |
XPath 1.0 函数
XPath 1.0 定义了 27 个内置函数,分属四类:节点集、字符串、数字和布尔值。以下是编写查询时最常用的函数。所有函数均受本测试器及每个符合规范的实现支持。
| 函数 | 类别 | 说明 |
|---|---|---|
| text() | Node test | Selects text content of a node |
| position() | Numeric | Returns 1-based position in node set |
| last() | Numeric | Returns size of current node set |
| count() | Numeric | Counts nodes: count(//book) |
| contains() | String | contains(@class, "active") — substring match |
| starts-with() | String | starts-with(title, "The") — prefix match |
| normalize-space() | String | Strips leading/trailing whitespace |
| string-length() | Numeric | Returns character count of a string |
| sum() | Numeric | sum(//price) — totals numeric values |
| not() | Boolean | not(@disabled) — negation |
| name() | String | Returns element or attribute name |
代码示例
以下示例展示了如何以编程方式求值 XPath 表达式。每段代码均使用相同的 catalog.xml 结构,便于对比各语言的 API 差异。
const xml = `<catalog>
<book id="1"><title>1984</title><price>7.99</price></book>
<book id="2"><title>Dune</title><price>12.99</price></book>
</catalog>`
const parser = new DOMParser()
const doc = parser.parseFromString(xml, 'application/xml')
// Select all book titles
const result = doc.evaluate('//book/title', doc, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null)
let node = result.iterateNext()
while (node) {
console.log(node.textContent) // → "1984", "Dune"
node = result.iterateNext()
}
// Get a numeric value
const sum = doc.evaluate('sum(//price)', doc, null, XPathResult.NUMBER_TYPE, null)
console.log(sum.numberValue) // → 20.98from lxml import etree
xml = """<catalog>
<book id="1"><title>1984</title><price>7.99</price></book>
<book id="2"><title>Dune</title><price>12.99</price></book>
</catalog>"""
tree = etree.fromstring(xml.encode())
# Select elements by attribute
books = tree.xpath('//book[@id="1"]/title/text()')
print(books) # → ['1984']
# Use predicates with position
first = tree.xpath('//book[1]/title/text()')
print(first) # → ['1984']
# Boolean check
has_cheap = tree.xpath('boolean(//price[. < 10])')
print(has_cheap) # → Trueimport javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.*;
import org.w3c.dom.*;
var factory = DocumentBuilderFactory.newInstance();
var builder = factory.newDocumentBuilder();
var doc = builder.parse(new java.io.File("catalog.xml"));
var xpath = XPathFactory.newInstance().newXPath();
// Select node set
NodeList titles = (NodeList) xpath.evaluate(
"//book/title", doc, XPathConstants.NODESET
);
for (int i = 0; i < titles.getLength(); i++) {
System.out.println(titles.item(i).getTextContent());
// → "1984", "Dune"
}
// Evaluate to number
double total = (double) xpath.evaluate(
"sum(//price)", doc, XPathConstants.NUMBER
);
System.out.println(total); // → 20.98# Select all book titles xmllint --xpath '//book/title/text()' catalog.xml # → 1984Dune # Select by attribute xmllint --xpath '//book[@id="2"]/title' catalog.xml # → <title>Dune</title> # Count nodes xmllint --xpath 'count(//book)' catalog.xml # → 2 # Using xmlstarlet for formatted output xmlstarlet sel -t -v '//book/title' -n catalog.xml # → 1984 # → Dune