XMLをDOMとして扱う

たまにあるけど毎度忘れて検索するハメになるのでメモ。
リファレンスはXML DOM Objects/Interfaces。といってもMSのURLはコロコロ変わるからURL載せてもあんまり意味ない。

まずはオブジェクトを作成

var xmlDoc = new ActiveXObject("Msxml2.DOMDocument.3.0");
var xmlDoc = new ActiveXObject("Msxml2.DOMDocument.6.0");
var xmlDoc = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.3.0");
var xmlDoc = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.6.0");

まず指定するProgIDだがリファレンスにはこれだけ載ってる。3.0とか6.0はVerだからいいとしてFreeThreadedDOMDocumentつーのはマルチスレッドの必要があるならならこっち使えって事らしい。WSHでそんな事出来ないので関係ない。

XMLをロード

xmlDoc.load(path);
xmlDoc.loadXML(xml);

loadメソッドはXMLのPathを指定するのであってXMLドキュメント自体を指定するのではない。web上にあるXMLを読み込むような場合はloadXMLで読み込む。共に戻り値はBoolean。読み込みの成功失敗はこれで判断出来る。

XMLロード時のオプション

xmlDoc.async = false;
xmlDoc.validateOnParse = false;
xmlDoc.resolveExternals = false;
async 同期非同期フラグ。非同期ならtrueでこれがdefalt。
validateOnParse XMLをパースする際のvalidなドキュメントであるかの妥当性検証のフラグ。
resolveExternals DTDのフラグ。

非同期で扱う事なんかあまりないだろうしXMLの厳密な検証なんてする事も少ないだろう。最近DTD自体が使われなくなっているのでこれもfalseでよし。この3行をおまじないと思ってloadの前に置いておけばいいだろう。

XPathで目的のデータを取得する場合

xmlDoc.setProperty("SelectionLanguage", "XPath");

selectSingleNodeやselectNodesで与える引数は互換性を確保する為にdefaltではXSLPatternとなっている。XSLPatternなんてもう廃止されて久しいんだけど。そんな訳でXPathを使うには上記の様なおまじないを唱える必要がある。

XMLにおける名前空間の問題

<?xml version="1.0" encoding="UTF-8" ?>
<RDF
  xmlns="http://purl.org/rss/1.0/"
  xmlns:dc="http://purl.org/dc/elements/1.1/">
  <item>
    <title>foo</title>
    <dc:description>bar</description>
  </item>
</RDF>

こんなXMLがあるとしよう。そこらのRSSをサンプルにして適当にこしらえたんだけど。この中のitem要素を抜き出したいが一体どうすればいい。とりあえずselectNodesで抜き出してみよう。

xmlDoc.selectNodes("//item");

うーん上手く動かない。調べると名前空間を指定しないと駄目らしい。名前空間はsetPropertyを使って設定する。

xmlDoc.setProperty("SelectionNamespaces", "xmlns='http://purl.org/rss/1.0/' xmlns:dc='http://purl.org/dc/elements/1.1/'");

そしてもう一度selectNodesで抜き出してみよう。やっぱり動かない。

結論を言うとitem要素には「xmlns="http://purl.org/rss/1.0/"」というprefixのない名無しの名前空間が設定されている。これを指定する必要があるがprefixがないので指定しようがない。仕方がないのでこうする。

xmlDoc.setProperty("SelectionNamespaces", "xmlns:defalt='http://purl.org/rss/1.0/'");
xmlDoc.selectNodes("//defalt:item");

名無しだった名前空間にdefaltというprefixを付けた。selectNodesでもdefalt:itemと名前空間を指定した。この適当に付けたprefixはaでもbでも識別できれば何でもいい。