XPath テスター
XPath式をXMLに対してテストし、一致するすべてのノードを確認
XML入力
XPathとは?
XPath(XML Path Language)は、XMLドキュメントからノードを選択するためのクエリ言語です。W3CがXSLT標準の一部として定義したXPathは、XMLドキュメントをノードのツリーとして扱い、そのツリーをたどるためのパスベースの構文を提供します。たとえば //book[@category="fiction"]/title というXPath式は、category属性が "fiction" に等しいbook要素の中にあるすべてのtitle要素を選択します。すべての主要なブラウザと多くのXMLライブラリがサポートするXPath 1.0は、1999年にW3C勧告として公開され、現在も最も広く使われているバージョンです。
XPath式は4種類の結果型のいずれかを返します。ノードセット、文字列、数値、またはブール値です。ノードセットは最も一般的な結果型で、0個以上のXMLノード(要素、属性、テキストノード、コメント、処理命令)を含みます。文字列、数値、ブール値の結果は、count()、sum()、contains() といったXPath関数やブール比較から得られます。この型システムにより、XPathはデータの抽出だけでなく、XSLTスタイルシートやXMLスキーマアサーション内の条件ロジック記述にも適しています。
バージョン1.0の式はあらゆる環境で動作します。JavaScriptのdocument.evaluate()、PythonのlxmlおよびElementTree、Javaのjavax.xml.xpath、PHPのDOMXPath、xmllintなどのコマンドラインツールがすべて対応しています。バージョン2.0および3.1はより豊富な型システムと関数を追加しますが、Saxonのような専用エンジンが必要です。デフォルトではバージョン1.0を使用してください。シーケンス、正規表現、高階関数が必要な場合にのみ2.0または3.1を検討し、SaxonまたはBaseXへの依存を受け入れてください。
オンラインXPath テスターを使う理由
正確な式を書くには、ドキュメント構造を理解し実際のデータに対してテストする必要があります。このツールはプロジェクトをセットアップしたりボイラープレートコードを書いたりせずに、式を繰り返し試せるインタラクティブな環境を提供します。
XPath テスターの使用例
XPath 軸リファレンス
軸は、現在(コンテキスト)ノードを基準としたナビゲーションの方向を定義します。完全な構文は axis::node-test[predicate] ですが、多くの開発者は省略形(//、@、..)を日常的に使用します。この表はすべての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 関数
この言語は、ノードセット、文字列、数値、ブール値の4カテゴリにわたる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 |
コード例
これらの例は、式をプログラムで評価する方法を示しています。各スニペットは同じ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