こうこく
作 ▸
改 ▸

JavaScriptで文字列をDOM要素に変換する

プレーンのJavaScriptHTMLの文字列をDOM要素に変換する方法。

jQuery使えばいいのだが……

関数にしたかったので、こういうのを書いてみました。引数のHTML文字列は文法エラーが無いこと前提です。

stringToDOMElements
/**
 * HTMLの文字列をNodeListに変換して返却
 * @param String HTMLの文字列
 * @return NodeList
 */
var stringToDOMElements = (function() {
	// 親にしてよい要素
	var parentTagNames = {
		title: 'head', base: 'head', link: 'head', meta: 'head', style: 'head',
		li: 'ul', dt: 'dl', dd: 'dl', figcaption: 'figure', rb: 'ruby', rt: 'ruby', rtc: 'ruby', rp: 'ruby',
		param: 'object', track: 'audio', area: 'map', caption: 'table', colgroup: 'table', col: 'colgroup',
		thead: 'table', tbody: 'table', tfoot: 'table', tr: 'tbody', th: 'tr', td: 'tr',
		optgroup: 'select', option: 'select', legend: 'fieldset',
	};
	return function(str) {
		str = str.replace(/[\r\n\t]/g, ''); // 改行コードとタブを全て除去
		
		// 先頭のタグ名に応じて親要素作成
		var parentTagName = 'div';
		var m = str.match(/^<([a-zA-Z]+)[ >]/);
		if (m !== null && m[1] !== undefined && parentTagNames[m[1]] !== undefined) {
			parentTagName = parentTagNames[m[1]];
		}
		var parentEl = document.createElement(parentTagName);

		// 親要素のinnerHTMLに突っ込んでDOM要素に変換
		parentEl.innerHTML = str;
		return parentEl.childNodes;
	};
})();

使用例

// 使用例その1
var result1 = stringToDOMElements(`<ul>
	<li>ほにゃ</li>
	<li>ふにゃ</li>
</ul>
<div>へにゃ</div>`);

console.log(result1[0].firstElementChild.innerHTML); // ほにゃ
console.log(result1[1].innerHTML); // へにゃ


// 使用例その2
var result2 = stringToDOMElements(`<tr>
	<td>データA-1</td>
	<td>データB-1</td>
</tr>
<tr>
	<td><span class="aiai ueue">データA-2</span></td>
	<td>データB-2</td>
</tr>`);

console.log(result2[0].childNodes[1].innerHTML); // データB-1
console.log(result2[1].childNodes[0].childNodes[0].innerHTML); // データA-2
console.log(result2[1].childNodes[0].childNodes[0].classList[1]); // ueue

備考

やや変な感じになってしまったので、以下経緯。

  1. 最初に改行コードとタブ文字を除去してるのは、文字列状態での要素間の改行コードやタブが、最後に childNodes で取得した時にテキストノード扱いされていて邪魔だったから。
  2. innerHTML に突っ込むために一時的に生成している親要素は、文字列の先頭の要素に応じて切り替えてる。div 一辺倒だと、ブラウザによっては (?) 文法エラーになって無視されてしまうから。

2つ目の件はChromeでしか確認してません。Chromeだと div の子供にいきなり tr 要素を突っ込んだり、同様に div の子供に tbody 要素を突っ込んだ時に無視されて、剥き出しのテキストノードしか残りませんでした。でもほとんどの場合はそうはならなかったので、ここまで細かく親要素を切り替えなくても大丈夫だとは思います。

各要素に対してどういう親要素を設定できるかは、一応 HTML5.2 の仕様書 を見て確認しました。

この記事に何かあればこちらまで (非公開)