TL;DR
/**
* 条件に合ったコメントノードを取得します
* @license WTFPL
* @param {string} [pattern] - ヒットさせる文字列
* @param {Node} [region] - 検索するコンテキストノード
* @return {Comment[]} - コメントノードリスト
*/
const getCommentNodes = (pattern, region) => {
const context = region ? (d => {
d.append(region.cloneNode(true));
return d;
})(new Document()) : document;
const xPathResult = document.evaluate(
pattern ? `//comment()[contains(., "${pattern}")]` : '//comment()',
context,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null,
);
const result = [];
let {snapshotLength} = xPathResult;
while (snapshotLength--) {
result.unshift(xPathResult.snapshotItem(snapshotLength));
}
return result;
};
使用方法
const allComments = getCommentNodes(); // すべてのコメントノードを取得する
console.log(allComments); // すべてのコメントノード
console.log(allComments.length); // すべてのコメントノードの個数
console.log(allComments[0].textContent);
allComments[0].remove(); // 先頭のコメントノードを削除
console.log(getCommentNodes('ogp')); // コメントに「ogp」を含むすべてのコメントノードを取得する
console.log(getCommentNodes('', document.head)); // head 要素内のすべてのコメントノードを取得する
console.log(getCommentNodes('if IE 9', document.head)); // コメントに「if IE 9」を含む head 要素内のコメントノードを取得する
console.log(getCommentNodes('TODO', document.body)); // コメントに「TODO」を含む body 要素内のコメントノードを取得する
コメントノードを検索する
諸事情でページ内に存在するコメントノードをすべて削除したかったのですが、ナレッジがあまり見つけられなかったため忘備録として残しておきます。
コメントノードはXPathを使うことで簡単に検索できます。これを使えばすべての要素を取得してそれぞれのchildNodes
を走査する、なんて必要はありません。
document.evaluate()
JavaScriptでXPath
を使うにはdocument.evaluate()
を利用します。
第1引数にXPath構文を指定し、第4引数にXPathResult.ORDERED_NODE_SNAPSHOT_TYPE
を指定することで条件に合ったノードを登場順に取得できます。
contains()
コンテンツの中身を検査する場合は、XPathのcontains(attrName, value)
関数を利用します。
要素だった場合は第1引数に属性名、第2引数に含まれる文字列を指定しますが、コメントノードの場合は第1引数にピリオドを設定することでコメントノード内を検索できます。
参考
- Can I use document.evaluate ? ( IE not supported. )
- クローラ作成に必須!XPATHの記法まとめ - Qiita
- Document.evaluate() - Web API | MDN