web-dev-qa-db-ja.com

JSでHTML文字列をパースする

私は解決策を探しましたが、何も関連性がなかったので、ここに私の問題があります:

HTMLテキストを含む文字列を解析したいです。 JavaScriptでやりたいのですが。

私は このライブラリ を試しましたが、文字列からではなく、現在のページのHTMLを解析するようです。以下のコードを試すと、ページのタイトルが変わるためです。

var parser = new HTMLtoDOM("<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>", document);

私の目標は、私が文字列のように読んだHTML外部ページからリンクを抽出することです。

それを行うためのAPIを知っていますか?

211
stage

ダミーのDOM要素を作成し、それに文字列を追加します。そうすれば、DOM要素のように操作できます。

var el = document.createElement( 'html' );
el.innerHTML = "<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>";

el.getElementsByTagName( 'a' ); // Live NodeList of your anchor elements

編集:ファンを喜ばせるためにjQueryの答えを追加!

var el = $( '<div></div>' );
el.html("<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>");

$('a', el) // All the anchor elements
322

とても簡単です。

var parser = new DOMParser();
var htmlDoc = parser.parseFromString(txt, 'text/html');
// do whatever you want with htmlDoc.getElementsByTagName('a');

MDN によると、これをクロームで行うには、次のようにXMLとして解析する必要があります。

var parser = new DOMParser();
var htmlDoc = parser.parseFromString(txt, 'text/xml');
// do whatever you want with htmlDoc.getElementsByTagName('a');

現時点ではwebkitではサポートされていないので、Florianの回答に従う必要があります。ほとんどの場合、モバイルブラウザで動作することは不明です。

編集:今広くサポートされています

176
Cilan

編集:HTML、ヘッドとボディが削除されているので、以下の解決策はHTMLの "フラグメント"のためのものです。この問題に対する解決策はDOMParserのparseFromString()メソッドであると思います。


HTMLフラグメントの場合、ここにリストされている解決策はほとんどのHTMLに対して機能しますが、場合によっては機能しません。

例えば<td>Test</td>を解析してみてください。これはdiv.innerHTMLソリューションやDOMParser.prototype.parseFromStringやrange.createContextualFragmentソリューションでは動作しません。 tdタグがなくなり、テキストだけが残ります。

JQueryだけがそのケースをうまく処理します。

それで、将来の解決策(MS Edge 13+)はテンプレートタグを使うことです:

function parseHTML(html) {
    var t = document.createElement('template');
    t.innerHTML = html;
    return t.content.cloneNode(true);
}

var documentFragment = parseHTML('<td>Test</td>');

古いブラウザではjQueryのparseHTML()メソッドを独立したGistに抽出しました - https://Gist.github.com/Munawwar/6e6362dbdf77c7865a99

14
Munawwar
var $doc = new DOMParser().parseFromString($html, "text/html");
$As = $('a', $doc);
7
Mathieu

次の関数parseHTMLは次のいずれかを返します。

  • ファイルがDoctypeで始まる場合、a Document

  • ファイルがDoctypeで始まっていない場合は、a DocumentFragment となります。


コード :

function parseHTML(markup) {
    if (markup.toLowerCase().trim().indexOf('<!doctype') === 0) {
        var doc = document.implementation.createHTMLDocument("");
        doc.documentElement.innerHTML = markup;
        return doc;
    } else if ('content' in document.createElement('template')) {
       // Template tag exists!
       var el = document.createElement('template');
       el.innerHTML = markup;
       return el.content;
    } else {
       // Template tag doesn't exist!
       var docfrag = document.createDocumentFragment();
       var el = document.createElement('body');
       el.innerHTML = markup;
       for (i = 0; 0 < el.childNodes.length;) {
           docfrag.appendChild(el.childNodes[i]);
       }
       return docfrag;
    }
}

使い方 :

var links = parseHTML('<!doctype html><html><head></head><body><a>Link 1</a><a>Link 2</a></body></html>').getElementsByTagName('a');
6
John Slegers

ChromeとFirefoxでHTMLを解析する最も速い方法はRange#createContextualFragmentです。

var range = document.createRange();
range.selectNode(document.body); // required in Safari
var fragment = range.createContextualFragment('<h1>html...</h1>');
var firstNode = fragment.firstChild;

可能であればcreateContextualFragmentを使用し、それ以外の場合はinnerHTMLにフォールバックするヘルパー関数を作成することをお勧めします。

ベンチマーク: http://jsperf.com/domparser-vs-createelement-innerhtml/3

5
Joel Richard

JQueryを使いこなすのであれば、HTMLの文字列から分離されたDOM要素を作成するためのいくつかの素晴らしい機能があります。これらは通常の方法で問い合わせることができます。

var html = "<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>";
var anchors = $('<div/>').append(html).find('a').get();

編集 - ちょうど正しい@フロリアンの答えを見ました。これは基本的にまさに彼が言ったことですが、jQueryを使います。

2
jmar777
const parse = Range.prototype.createContextualFragment.bind(document.createRange());

document.body.appendChild( parse('<p><strong>Today is:</strong></p>') ),
document.body.appendChild( parse(`<p style="background: #eee">${new Date()}</p>`) );
2
AnthumChris