JavaScript で XPath を使って XML を Parse する

XML をクライアントサイドで操作したい場面があったので、 JavaScript で XML を扱う方法について調べてみました。

基本的には上のリファレンスの通りです。

やりたいこと

今回の対象とするのは次のような XML です。

<?xml version="1.0" encoding="utf-8"?>
<cities version="1.0.0">
    <city pref="1" city="1">札幌</city>
    <city pref="1" city="2">函館</city>
    <city pref="1" city="3">小樽</city>
    <city pref="1" city="4">室蘭</city>
    <city pref="2" city="1">弘前</city>
    <city pref="2" city="2">青森</city>
    <city pref="2" city="3">八戸</city>
    <city pref="3" city="1">盛岡</city>
    <city pref="3" city="2">釜石</city>
    <city pref="3" city="3">宮古</city>
</cities>

この XML から、 prefcity の値をもとに、都市の名前を取る ということをやりたいです。

実装

上の XML が cities.xml として、やりたいことを JavaScript で実現するためのコードです。

const xhr = new XMLHttpRequest();
xhr.addEventListener('load', () => {
    var citiesXml = xhr.responseXML;
});
xhr.addEventListener('error', () => {
    console.error('Failed to load xml.');
});
xhr.open('GET', '/path/to/cities.xml');
xhr.send();

function getCityName(prefId, cityId) {
    return citiesXml.evaluate(`//city[@pref='${prefId}' and @city='${cityId}']`, citiesXml, null, XPathResult.STRING_TYPE, null).stringValue;
}

console.log(getCityName(1,4));

// => 室蘭

詳細

documentevaluate() を使います。
evaluatevar xpathResult = document.evaluate( xpathExpression, contextNode, namespaceResolver, resultType, result ); のような形で使います。

引数は次の通り。

  • xpathExpression: XPath の文字列を指定します。
  • contextNode: 対象となる document を指定します。
  • namespaceResolver: 対象の document が名前空間を持っている場合に指定します。持っていなければ null を指定します。
  • resultType: 返却されるべき XPathResult のタイプを指定します。上の例では文字列が返されるべきなので STRING_TYPE を指定していますが、一般的には ANY_TYPE を指定します。実際にどのタイプが返却されたかは、 XPathResult オブジェクトの resultType の値で確認できます。ノードが返却される場合は、 UNORDERED_NODE_ITERATOR_TYPE になります。
  • result: 既存の XPathResult を指定した場合は、そのオブジェクトを再利用します。 null を指定した場合は、新たに XPathResult オブジェクトが作成されます。

XPath の指定方法として、今回は 2 つの属性の条件を指定しています。
単独の属性指定であれば city[@pref='${prefId}'] ですが、複数になる場合は and でつなぎます。

ひとこと

無事に JavaScript で XPath を使って XML をパースすることができました。
今回は XPathResult が STRING_TYPE の例でしたが、他のタイプ、特に UNORDERED_NODE_ITERATOR_TYPE での挙動についてはまだよくわかっていないので、別途 色々試してみようと思います。

comments powered by Disqus