重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

【GOLF me!】初月無料お試し

var dummyTag = document.createElement("div")
dummyTag.innerHTML = "<AAA>BBB</AAA>";
としたときに、dummyTag.childNodes の動作がfirefoxとIEで異なります。
firefoxでは、childNodes の要素は1つでAAAのみ。BBBはAAAの子要素になります。
IEでは、childNodesの要素は3つで、AAA, BBB, /AAA がそれぞれ要素とされてしまうようです。
AAAをタグとして解釈しているfirefoxの動作の方が自分にとって好ましいのですが、
IEでもこのように認識させる方法はないものでしょうか。
なお、WinXP SP3, firefox10, IE8 で確認しています。

A 回答 (8件)

先に createElement('AAA') しておく、というのならあります。

HTML(5) の新要素を IE8 以下に認識させるときに用いられています。ただし、フレームをまたぐなどした別文書には効果がありません。


そもそも「HTML として」なら、IE(ver. 8 以下)の振る舞いも仕方ない面があるでしょう。「HTML としては」不正なデータなのですから、エラー処理が走ります。

HTML 2.0-4.01 規定では「未知のタグは無視する」とだけあり、具体的な処理方法および DOM 木にどう反映すべきかまでは書かれていません。未知のタグセットであっても要素ノードとして解釈するのは、XML および HTML(5) です。

どうしても AAA 要素なるものを DOM 断片として扱いたければ、XML として処理して下さい。当然ながら、XML 要素ノードには innerHTML などありませんので、IE/MSXML なら xml プロパティ、DOM Level 3 なら markupContent プロパティ(サポートしている実装を見たことがありませんが)があります。でなければ、いちいち createElement() して下さい。

XML 処理したくなければ(あるいは整形式でないのなら)、既存の HTML 要素を用いて下さい。


なお、childNodes にはちゃんと定義がありますので、そこから外れた振る舞いは「バグ」と見なせます。「ブラウザごとに違う」で終わるのでなく、それが規定の動作であるのか、それとも規定から外れた振る舞いであるのか、を把握して下さい。後者は将来的に修正される可能性が高く、例外処理に回すべきものだからです。これは CSS を使うときも同じです。

とはいえ今回の件は childNodes の定義よりもっと下層、マークアップデータの解析レベルの問題です。
    • good
    • 0
この回答へのお礼

innerHTMLとして読み込ませたいテキストは
状況によって内容がことなり、しかも、
その子要素を再帰的に処理する必要があるため、
createElement()することはできないという事情があります。
HTML5として解釈するというのは、古いブラウザだと対応してないですよね。
XMLとしてテキストを読み込んで要素ノードとして解釈し、
処理を実施した後に結果をinnerHTMLに入れるようにすれば、
可能なのでしょうか。

お礼日時:2012/02/09 17:57

すでに別質問に移っておられますが、とりあえず。



No.7 お礼より:
> 実行時に他のjsonファイルを参照しながら非HTMLタグをHTMLタグに変換

サーバ側と何回往復するかによりますが、もしクライアント側だけで完結を目指すのなら、データ保持層(モデルとしての XML)と、ブラウザ表示層(ビューとしての HTML)を分離する必要があります。ぶっちゃけ、XSLT でやった方が楽です。

基本的に、HTML と XML(すなわち未知要素)の混在という手段は「ない」ものと考えて下さい(最近、この問題についての W3C Report も出ました)。どうしてもそれが必要なら XHTML でやることになりますが、何度も繰り返しております通り、IE の HTML パーサを通しては駄目です。HTML パーサを通すのは、それを表示するときだけです。

私の結論としてましては、全てを X(HT)ML でやるか(ブラウザに表示させるときのみ HTML 変換して innerHTML を使う)、全てを HTML でできるよう未知要素を使わないようにするか、どちらかしかない、としておきます。

※一応、IE 5.0-8.0 には XML Data Island というのがあり、<script type="text/html">...</script> または独自拡張の xml 要素を置くことで、HTML 文書内に XML 文書を埋め込めます(IE9 で廃止されました)。しかし、ご要望とはまた少し違うでしょう。
    • good
    • 0
この回答へのお礼

<http://ejohn.org/blog/pure-javascript-html-parse …
にあるhtmlparser.jsを参考に、パーサを実装しました。
ご回答ありがとうございました。

お礼日時:2012/02/17 17:27

今気付いたのですが、ひょっとしてご質問の意図は <A>BBB</A> から DOM 文書木を構築できれば良いだけで、HTML 語彙との混在は別に考えていなかったりしますか?



であれば、No.6 に書いた通り、IE なら DOMDocument、それ以外なら DOMParser を使えば良いだけです。


問題になるのは、木と木を結合するときです。Firefox は(大雑把に)XML ノードと HTML ノードが一元管理されていますので、割と自由に切り貼りできます。しかし、IE は MSXML と MSHTML が別機構ですので、自由にノードを切り貼りすることができません。

本来、このために DOM Level 2 の document.importNode() があるのですが、これはこれで微妙な問題があります(略)。だから、MSXML 側のノードをいったん文字列に直し、MSHTML 側の innerHTML に解析させるという二度手間を行うことになります。

このとき、innerHTML による HTML 解析が走る以上、IE7 以下にとって未知の要素は使えません。なので、No.6 では MSXML ノードの文字列化がてら、HTML の span 要素に変換したわけです。

innerHTML は万能のプロパティではないです。かなり限定された用途にしか使えません。
    • good
    • 0
この回答へのお礼

丁寧なご回答ありがとうございます。
やりたいことは、HTMLタグと非HTMLタグが混在したHTMLライクなドキュメントがあり、実行時に他のjsonファイルを参照しながら非HTMLタグをHTMLタグに変換して、変換結果を表示する、というものです。非HTMLタグは何度か非HTMLタグに変換されたあとに最終的にHTMLタグに変換されることもあり、再帰的な処理が必要になります。
HTMLライクなドキュメントの階層構造を再帰的に辿りながら変換する際に、childNodeで辿るようにFireFoxで確認しながら実装したのですが、IEで確認したところ思うように動かず、childNodeの挙動が違うことに気づいた次第です。
domなり、MSXMLなり、調べていますが、この辺りの経験があまりなく、推奨される方法がありましたら教えてください。

お礼日時:2012/02/13 13:35

No.2 お礼より:


> XMLとしてテキストを読み込んで要素ノードとして解釈し、処理を実施した後に結果をinnerHTMLに入れる

ですから、これは DOM の問題ではなく、ソース解析レベルの問題だということを念頭に置いて下さい。IE6/7 が HTML 文書内の未知のタグ(開始タグであれ終了タグであれ)をひとつの空要素と見なす以上、未知のタグのまま扱うことはできません。基本的に方法はひとつ、既知のタグに置き換えてやることです。

下記では、A 要素を HTML の span[@class="A"] 要素に変換します。

var xmlDoc;
var xmlString =
 '<dummyRoot>' + '<AAA>BBB</AAA><AAA>CCC</AAA>' + '</dummyRoot>';

var xslDoc;
var xslString =
 '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">' +
  '<xsl:output method="html"/>' +
  '<xsl:template match="/">' +
   '<xsl:apply-templates select="dummyRoot/*"/>' +
  '</xsl:template>' +
  '<xsl:template match="*">' +
   '<span class="{local-name()}">' +
    '<xsl:apply-templates/>' +
   '</span>' +
  '</xsl:template>' +
 '</xsl:stylesheet>';

var htmlDoc = document;
var htmlDiv = htmlDoc.createElement('div');

try {
 xmlDoc = new ActiveXObject('Msxml2.DOMDocument.3.0');
 xmlDoc.loadXML(xmlString);
 xslDoc = new ActiveXObject('Msxml2.FreeThreadedDOMDocument.3.0');
 xslDoc.loadXML(xslString);
 htmlDiv.innerHTML = xmlDoc.transformNode(xslDoc);
}
catch (err) {
 var proc = new XSLTProcessor;
 var parser = new DOMParser;
 xmlDoc = parser.parseFromString(xmlString, 'application/xml');
 xslDoc = parser.parseFromString(xslString, 'application/xml');
 proc.importStylesheet(xslDoc);
 htmlDiv.appendChild(proc.transformToFragment(xmlDoc, htmlDoc));
}

alert(htmlDiv.innerHTML);

もちろん、こんな手間をかけるくらいなら最初から span[@class="A"] で出力した方が早いです。@class の他、@itemprop、@rel、@content、@data-* なども候補になるでしょう。


なお、No.2 で触れた MSXML の xml プロパティですが、読み取り専用であることを失念しておりました。失礼しました。

ちなみに、実装的には HTMLUnknownElement がなくても Element で返せば十分です。HTML(5) で HTMLUnknownElement をわざわざ設けたのは、未知の要素でも innerHTML など HTML-DOM API を使えるようにするためです。とはいえ、基本的に文字列処理を避けるべきなのは言うまでもありません。

ここから分かるように、HTML(5) では未知の要素の解析・処理方法も定められています。3.2.2 節、12.2.4.10 節、15.3.4 節などを参照して下さい。でないと将来、要素が追加されたときに、またも今の IE のような扱いになりますので。
    • good
    • 0

IE8 はhtmlファイルに "<AAA>BBB</AAA>" を直書きしても不正な要素を(制作者の期待通りに)認識しません。


http://fiddle.jshell.net/hDNkE/2/

最近のブラウザは HTML 5 規定に従い、HTMLUnknownElement インターフェースを持つ HTMLElement を返します。(Google Chrome 16, Firefox 10.0, Opera 11.61 で確認)
http://www.whatwg.org/specs/web-apps/current-wor …

IE8 は不正な要素に対して [object HTMLUnknownElement] を返す実装をしていますが、質問者さんが期待する動作はしていないようです。
HTML (HTML5) がなかった時代のブラウザですから仕方ないですが…。
http://www.asahi-net.or.jp/~sd5a-ucd/rec-html401 …

最も、対象ブラウザ全てが HTML (HTML5) に従うようになったとしても "<AAA>BBB</AAA>" は Invalid な文字列です。
"<AAA>BBB</AAA>" というXML文字列をDOMに挿入せずに処理をした上で HTML に変換し、DOMに挿入させるのが一般的な対応だと思います。

でなければ、XHTML文書にしてXMLを挿入しても良いですが、IE8- は XHTML を認識できないため、XML文書として扱わせるようにトリックを使う必要があります。
具体的には IE8- 向けに「Content-Type: application/xml」を出力して XML 文書として扱わせます。
http://www.w3.org/MarkUp/2004/xhtml-faq#ie
    • good
    • 0

IEはタグとして認識してます。


ただそれが、空要素(<img>などと同じ)か、空要素ではない<span>などと同じかの違いだけです。

HTMLの文法では未定義タグの扱いをどうするかは定義されていません。
完全にブラウザ依存です。
(なお、タグ属性の扱いに付いてもブラウザ依存です。)


HTMLで定義された要素を使うのをお勧めしますが、どうしても未定義タグを使用するなら、createElementで可能です。

var tmp=document.createElement('AAA');

var div=document.createElement('div');
div.innerHTML='<aaa>あいうえお</aaa>';


より厳格にするには、詳しくは、いわゆる"html5.js"を参考にしてみてください。
HTML5タグをサポートしないIEで、<section>や<article>などを、空要素ではなくいわゆるインライン要素として認識させるためのスクリプトです。
(ブロック要素にみせかけるには、display:blockをスタイルシートで指定する)
googlecodeなどに登録されている物では、DOCTYPEやXML/HTMLモードなどで区別しているのか、そうとうややこしい処理を行っている物もあります。

ファイル名として"html5.js"が使われることが多いので、そのファイル名で検索したらたくさん出てきます。

--------
逆に、Fxで空要素として認識させる方法はたぶんありません。

<p><mytag>あいうえお</p>

上記は、Fxは<p><mytag>あいうえお</mytag></p>として認識します。
    • good
    • 0
この回答へのお礼

詳しい回答ありがとうございます。
どうもIEの動きが掴めないのですが・・・。
IEが空要素として認識しているのであれば、
以下を実行した場合、0=AAAから始まると思います。
また、var tmp=document.createElement('AAA');
があってもなくても動作は変わらないようです・・・。

<html>
<head>
<title>テスト</title>
</head>
<body>
<div>本文</div>
<div id="xx">あああ</div>
<script type="text/javascript">
var ret = new Array();
//var tmpA=document.createElement('AAA');
//var tmpB=document.createElement('BBB');
var dummyTag = document.createElement("div")
dummyTag.innerHTML = "<AAA>a</AAA><BBB>b</BBB><CCC>c</CCC>";
for ( var i = 0; i < dummyTag.childNodes.length; i++){
ret[ret.length] = i + "=" + dummyTag.childNodes[i].nodeName;
}
var res = ret.join('');
document.getElementById("xx").innerHTML = res;
</script>
</body>
</html>

childNodeエンティティを上書きする(できるのか分かりませんが)か、
innerHTMLに相当するテキストをタグかどうか解釈して
createElement するしかないものでしょうかね。

お礼日時:2012/02/10 17:57

つまりこういう処理



var dummyTag = document.createElement("div")
var BBB=document.createTextNode("BBB");
var AAA=document.createElement("AAA");
AAA.appendChild(BBB);
dummyTag.appendChild(AAA);

この回答への補足

innerHTMLとして読み込ませたいテキストは
状況によって内容がことなるため、
createElement()で対応できないという事情があります。
ご丁寧に作成いただいたのに申し訳ないです。

補足日時:2012/02/09 17:58
    • good
    • 0

>IEでもこのように認識させる


スクリプトでブラウザの動作を変更できたら
どうなると思います?
誰もそんな恐ろしいブラウザは使いません。

しょうがないから自分でブラウザを識別して
同じ結果になるようにプログラムしている
のが現状です。ブラウザごとに微妙に違う
ところはChildNodesだけではありませんしね。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!