IEでdocument.selectNodesみたいなもの?



0   名前: ラブーフ : 2006/08/27(日) 08:48  ID:mGMjLPPf
IE以外の今どきのブラウザでは、XPATHとして、document.evaluateを使って、表示しているページの
nodeリストを取得、更にこれをJavaScriptで普通に扱えますよね。
IEでは、これはできないのでしょうか?ActiveXを使っても良いのですが、なかなか上手い方法が
見つかりません。具体的には、ページの中に、

<div class="foo">
<p>これこれ</p>
</div>

みたいなやつがあるとして, document.evaluate が使えるなら、

 var child = document.evaluate('//div[@class="foo"]', document, null, 0, null);

で child.innerHTML とすれば、"<p>これこれ</p>" を取得できますよね。これと同じことを
IEでも「XPATHのexpression」を使って取得したいのです。キモは'//div[@class="foo"]'みた
いなXpathの表現を用いたいということです。

 var child = document.selectNodes('//div[@class="foo"]');

なことが出来ると最高なんですが。

1   名前: m035 ◆Wpzr1YKOiq : 2006/08/27(日) 08:48  [URL]  ID:4KIacXXc
http://getelementsby.com/

http://my-chunqiu.cocolog-nifty.com/html/javascript-behaviour.html
は参考になるかも知れません。

2   名前: ラブーフ : 2006/08/27(日) 08:48  ID:mGMjLPPf
m035さん、レスありがとうございます。
挙げていただいたサイトは、すでにチェックしました。検索しても
ひとつも出てこないところを見ると、無理なようですね。。
IEがDOM3をサポートすれば済む話なんですが、数年先になりそうなので。
 やはり、document.getElementBySelector() ですかねぇ。

苦し紛れに、以下のようなやつを作りましたが、やはりHTMLElementとは
みなしてくれず、

child.text では、テキスト文字列を取得できるものの、child.innerHTML
はundefinedとなります。あきらめるか。。

function query(xpath){
var _xml = document.createElement("xml");
var r, _self = "";
var r = new ActiveXObject("Microsoft.XMLHTTP");
r.open("get", d.location, false);
r.send(null);
if(r.responseText){
_self = r.responseText.replace(/[\r\n]/g,'').replace(/.*<body.*?>(.*?)<\/body><\/html>$/, "$1");
}
var xmlString = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">'
+ '<xsl:template match="*">'+_self+'</xsl:template></xsl:stylesheet>';
_xml.loadXML(xmlString);
d.body.appendChild(_xml);
var xmlDoc = _xml.XMLDocument;
d.body.removeChild(_xml);
return xmlDoc.selectNodes(xpath);
}

3   名前: Pid : 2006/08/27(日) 08:48  ID:qX78Rjxr
鈍亀レスかつ >>2 と全く同じアプローチですが,とりあえず外部に XML 文書を生成して,HTML 文書の中身をコピーしてみました。

データの取得はできますが,元文書への反映は当然ながらできません (^^;)。

if ('undefined' == typeof document.evaluate && typeof ActiveXObject != 'undefined')
    document.evaluate = function (expression, contextNode, resolver, type, result) {
        try {
            var d = new ActiveXObject ('Msxml2.DOMDocument');
            var s = contextNode.outerHTML;
            
            // IE の inner/outerHTML は XML 整形式には程遠い
            s = s.replace (/<([^\/][^>]+)>/g, function (m, c) {
                return '<' + c.replace (/([^\s]+)=([^'"\s]+)/g, '$1="$2"') + '>'; // "'
            } );
            s = s.replace (/<(area|base|basefont|br|col|frame|hr|img|input|param)(\s*[^>]*)>/gi, '<$1$2 />');
            
            d.async = false;
            d.loadXML (s);
            d.setProperty ('SelectionLanguage', 'XPath');
            
            return d.documentElement.selectNodes (expression);
        } catch (e) {
        }
    };


MSIE には,DOM ツリーをシリアライズする仕組みってないんでしたっけ(Opera なら DOM3 Load&Save が使えますし,Gecko なら XMLSerializer があります)。いずれにせよ,DHTML 時代の遺物である innerHTML は,個人的には好きじゃないのですが (^^;)。

4   名前: Pid : 2006/08/27(日) 08:48  ID:qX78Rjxr
別の方面からのアプローチを考えてみます。

var c, child = document.evaluate (
    '//div[@class="foo"]',
     document.documentElement,
     null,  // HTML only
     XPathResult.ORDERED_NODE_ITERATOR_TYPE,
     null
);

while (c = child.iterateNext ()) {
    // ...
}


は,TreeWalker として表現すれば以下のようになります。

var c, child = document.createTreeWalker (
    document.documentElement,
    NodeFilter.SHOW_ELEMENT,
    function (n) {
        if ('DIV' == n.tagName && 'foo' == n.className)
            return NodeFilter.FILTER_ACCEPT;
        else
            return NodeFilter.FILTER_SKIP;
    },
    false
);

while (c = child.nextNode ()) {
    // ...
}


ということは,XPath→NodeFilter に変換する仕組みを用意すれば,XPath の皮をかぶった TreeWalker を使えるようになるはずです。


さて,いつもの如く IE は DOM2 Traversal に対応していませんが,この API は比較的簡単に作成することができます。たとえば
http://web.archive.org/web/20050308112429/http://www.dithered.com/javascript/dom2_traversal/index.html
から,IE で DOM2 Traversal を使うライブラリを拾えます。あとは,XPath パーザさえ準備できれば OK です。たぶん (^^;)。

ちなみに,ある範囲内・条件内のツリーだけを操作したい場合にはトラバーサル機構が欠かせませんので,TreeWalker のような仕組みは絶対に手元に置いておいた方が良いです(DOM3 XPath だけでなく,DOM2 Range も TreeWalker でエミュレーションできます……ある程度までなら)。

5   名前: Pid : 2006/08/27(日) 08:48  ID:qX78Rjxr
>>3
> データの取得はできますが,元文書への反映は当然ながらできません

誤解を招く表現でしたが,>>3 の戻り値は HTMLElement ではありませんので,innerHTML へのアクセスは不可です。

XML 整形式から逸脱しない (X)HTML であれば,DOM ツリーのビルド⇔シリアライズされた文字列を相互変換するメソッドは,比較的簡単に作成できます。「innerHTML のようなもの」を自作してしまうのも一つの手でしょう。

6   名前: ラブーフ : 2006/08/27(日) 08:48  ID:mGMjLPPf
Pidさん、レスありがとうございます。
IEでは、どうしてもエミュレーションに頼らざるを得ませんよねぇ。
エミュレーションって、かなりスピードが落るのが痛いですね。
でも、ロジック的には、興味深いです。
IEが、nativeで他のモダンなブラウザ並の実装をしてくれれば何でもない話なんですけどね。。
IE7で、"new XMLHttpRequest()" をサポートしたといっても、その取り巻きのDOM XPathが
使えないんじゃ、そんなに意味ないですから(結局、ActiveXに頼らざるを得ない)。

>「innerHTML のようなもの」を自作してしまうのも一つの手でしょう。

脱線しますが、これに関して、あるノードの内容を取得するには、innerHTMLを使うのが楽では
ありますが、IEでは、すべて大文字になったり、Firefoxでもimgタグの閉じタグがなくなったり
して、「ありのまま」を取り出せません。なので、以下の様な関数を作ってみました。

function getInnerHTML(node){
  var str = '', x = 0, nodes = node.childNodes, X = nodes.length;
  var _attributes = [];
  while(x < X){
   var _node = nodes[x];
   switch (nodes[x].nodeType){
    case 1: // エレメントノード
     var tag = _node.nodeName.toLowerCase();
     var _innerHTML = _node.parentNode.innerHTML;
     var m = new RegExp("<"+tag+" +?([^>]*?)>", "i").exec(_innerHTML);
     var attrs = m[1].replace(/^\s/, '').split(/\s/);
     var i = 0, l = attrs.length;
     str += ("<" + tag);
     while(i < l){
      var a = attrs[i].split(/=/);
      if(a[0]!= "") str += ' '+a[0]+'="'+a[1].replace(/"/g, '')+'"';
      i++;
     }
     if(_node.childNodes.length == 0 && /^(INPUT|HR|BR|IMG)$/.test(_node.nodeName)){
       str += " />";
     } else str += '>' + getInnerHTML(_node) + '</' + tag + '>';
     break;
        
    case 3: // テキストノード
      if(/^[\r\n\t ]+$/.test(_node.nodeValue)) break;
      str += _node.nodeValue;
      break;
      
    case 4: // CDATAセクション
      str += "<![CDATA[" + _node.nodeValue + "]]>";
      break;
          
    case 5: // 実体参照ノード
      str += "&" + _node.nodeName.toLowerCase() + ";"
      break;

    case 8: // コメントノード
      str += "<!--" + _node.nodeValue + "-->"
      break;
  }
  x++;
  }
  return str;
}


このままだと、Firefoxとかで、空白文字が無視されてしましますが。空白文字の扱いがIEと異なる
ところですよね。まぁ、空白文字もノードとみなすというのは、正統であるとは思いますが。

7   名前: Pid : 2006/08/27(日) 08:48  ID:qX78Rjxr
なるほど,面白いですね。

たぶん「HTML ユーザエージェントとしての」IE は,もう W3C DOM 周辺を実装する気がないんじゃないかと邪推してみたり(IE7 も DOM2 Events すらサポートしてないみたいですし)。


>>3
> MSIE には,DOM ツリーをシリアライズする仕組みってないんでしたっけ

IXMLDOMElement.xml というプロパティが XML 文字列を返すようですね(読み取り専用ですが)。
http://msdn.microsoft.com/library/en-us/xmlsdk/html/31f7af53-6c3f-4a3e-a503-8aed9c4b270e.asp

そうすると,>>2 のラブーフさんの方法でいけそうな気がしましたが,どうでしょう。

http://webfx.eae.net/dhtml/xmlextras/xmlextras.html
http://sarissa.sourceforge.net/doc/

8   名前: sevi- : 2006/08/27(日) 08:48  ID:A5/hQl8Z
つまりこういう事がしたいという事だろうか.

<?xml version="1.0" encoding="Shift_JIS"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Untitled Page</title>
	<script type="text/javascript">
	<!--
		function selectNodes(queryString)
		{

			function getHTMLNode(node)
			{
				switch(node.nodeType)
				{
					case 2:
						var nodes_ele = doc.selectNodes("//*[@*[name()='"+node.nodeName+"']]");
						var node_ele;
						for(var i=0; i<nodes_ele.length; i++)
						{
							node_ele = nodes_ele[i];
							if(node_ele.selectSingleNode("@*[name()='"+node.nodeName+"']") == node)
								return getHTMLNode(node_ele).attributes[node.name];
						}
						break;
					default:
						var list_position = new Array();
						var node_before;
						var iPosition;
						while(node != doc.documentElement)
						{
							iPosition = 0;
							node_before = node.previousSibling;
							while(node_before != null)
							{
								iPosition++;
								node_before = node_before.previousSibling;
							}
							list_position.push(iPosition);
							node = node.parentNode;
						}
						var node_html = document.documentElement;
						while(list_position.length > 0)
							node_html = node_html.childNodes[list_position.pop()];
						return node_html;
				}
				return null;
			}

			var doc = new ActiveXObject("MSXML2.DOMDocument");
			doc.setProperty("SelectionLanguage", "XPath");
			doc.load(location.href);
			var nodes = doc.selectNodes(queryString);
			var node_html;
			var list_return = new Array();
			for(var i=0; i<nodes.length; i++)
			{
				node_html = getHTMLNode(nodes[i]);
				if(node_html != null)
					list_return.push(node_html);
			}
			return list_return;
		};
		function test()
		{
			var nodes;
			nodes = selectNodes("//*[name()='div']/@*");
			alert(nodes[0].nodeName);
			nodes = selectNodes("//text()");
			alert(nodes[1].nodeValue);
			nodes = selectNodes("/*");
			alert(nodes[0].outerHTML);
		}
	//-->
	</script>
</head>
<body onload="test();">
	<div id="d" class="a">test</div>
	<span>ああああ</span>
</body>
</html>


思いつくまま書いたのでどこかおかしいかもしれないが、おおむね以下のような手順で実現している.

・操作対象文書をXHTMLで構築
・ActiveXOBjectを用い、MSXMLDOMDocumentを生成、location.hrefを引数に文書をXML文書として読み込ませる
・MSXMLDOMDocument.selectNodesを呼び出し、取りあえずノードリストを取得
・集めた各ノードの内、属性ノード以外はツリー構造の位置を調べ、その情報を元にHTML文書を逆順に辿り取得し配列に放り込む.
・集めた各ノードの内、属性ノードはまず同ノードを有する要素を探し出し、その情報を元にHTML文書を逆順に以下略そして配列に叩き込む.
・配列を返す.

文書要素以下しか探索に対応しない(HTML文書の方が取れないので)、
HTML文書は最低XML1.0文書として正しく記述しなくてはならない、
HTML文書が完全に読み込まれてからでないと正しい結果が返らないorエラーが発生する可能性がある
等の制約はあるだろうが、大体これで望みは叶うのではなかろうか.

sevi-

9   名前: Pid : 2006/08/27(日) 08:48  ID:.vBytNbs
>>8
おお,感謝です (^^)(XHTML なら script 要素のコメントアウトは不要ですね)。

私は XPath パーザでも書こうと思いつつ,もう誰かが作ってるんじゃなかろうか……と思ったら案の定。
http://mcc.id.au/xpathjs/

var parser = new XPathParser;
var expression = parser.parse ('//node()[name()="DIV" and @class="foo"]');
var context = new XPathContext;
context.expressionContextNode = document.documentElement;

var result = expression.evaluate (context);

alert (result.tree.node.innerHTML);
alert (result.tree.right.node.innerHTML);  // もし結果が複数なら


DOM3 XPath の XPathResult.ORDERED_NODE_ITERATOR_TYPE のような感じでしょうか。変換・比較メソッドも用意されてますし,コード的にも継承(委譲)や(static でない)プライベート変数など,かなり面白そうでした。

10   名前: sevi- : 2006/08/27(日) 08:48  ID:PQukhZTw
>XHTML なら script 要素のコメントアウトは不要ですね

うん?CDATAセクションを使わないならつけた方が無難だと思うが.

追伸:

WhiteSpaceの解釈がMSXMLと異なるようで並び順を元に対象を特定するコード上にて
間違ったノードを選ぶ可能性があるようなのでWhiteSpaceを両者無視
する設定に修正したコードを以下に示す.

sevi-

<?xml version="1.0" encoding="Shift_JIS"?>
<html>
<head>
  <title>Untitled Page</title>
	<script type="text/javascript">
	<!--
		
		function selectNodes(queryString, document)
		{

			function getHTMLNode(node)
			{
				switch(node.nodeType)
				{
					case 2:
						var nodes_ele = doc.selectNodes("//*[@*[name()='"+node.nodeName+"']]");
						var node_ele;
						for(var i=0; i<nodes_ele.length; i++)
						{
							node_ele = nodes_ele[i];
							if(node_ele.selectSingleNode("@*[name()='"+node.nodeName+"']") == node)
								return getHTMLNode(node_ele).attributes[node.name];
						}
						break;
					default:
						var list_position = new Array();
						var node_before;
						var iPosition;
						while(node != doc.documentElement)
						{
							iPosition = 0;
							node_before = node.previousSibling;
							while(node_before != null)
							{
								iPosition++;
								node_before = node_before.previousSibling;
							}
							list_position.push(iPosition);
							node = node.parentNode;
						}
						var node_html = document.documentElement;
						var nodes_html;
						while(list_position.length > 0)
						{
							iPosition = list_position.pop();
							var nodes_html = node_html.childNodes;	
							for(var i=0; i<nodes_html.length; i++)	
							{
								node_html = nodes_html[i];
								if(node_html.nodeType != 3 || node_html.nodeValue.replace(/\s/g,"").length > 0)
									iPosition -= 1;
								if(iPosition < 0)
									break;
							}	
						}	
						return node_html;
				}
				return null;
			}
			
			if(document == null)
				document = window.document;
			var doc = new ActiveXObject("MSXML2.DOMDocument");
			doc.setProperty("SelectionLanguage", "XPath");
			doc.preserveWhiteSpace = false;
			doc.load(document.parentWindow.location.href);
			var nodes = doc.selectNodes(queryString);
			var node_html;
			var list_return = new Array();
			for(var i=0; i<nodes.length; i++)
			{
				node_html = getHTMLNode(nodes[i]);	
				if(node_html != null)
					list_return.push(node_html);
			}
			return list_return;
		};
		
		function test()
		{
			var nodes = selectNodes('//div[@class="foo"]', document);
			for(var i=0; i<nodes.length; i++)
				alert(nodes[i].innerHTML);
		}
		
	//-->
	</script>
</head>
<body onload="test();">

	<div class="foo">
	<p>これこれ</p>
	</div>

	<div class="foo">
	<p>あれあれ</p>
	</div>	

	<div class="foo">
	<p>そうそう、それそれ。</p>
	</div>
		
</body>
</html>

11   名前: Pid : 2006/08/27(日) 08:48  ID:.vBytNbs
> CDATAセクションを使わないならつけた方が無難だと思うが

text/html なら構わないのですが,application/xhtml+xml,application/xml だと,Mozilla 等では正しく無視されまする(IE はよく知りませんが)。

あと >>9 は DOM3 XPath のインタフェースも用意されてますた。さすがに遅いけど,面白い(非 static な private 変数云々は私の見間違いでした)。

12   名前: sevi- : 2006/08/27(日) 08:48  ID:PQukhZTw
>>11
いや、コメントを付け無いとスクリプト内の一部のコードをタグ等と誤認したりし、
XML文書として読み込めなくなる事が多々ある事を差している.

今回の手法は文書をXMLとして読み込ませているのでその問題は避けなくてはならない

sevi-

13   名前: Pid : 2006/08/27(日) 08:48  ID:.vBytNbs
その場合は script 要素内容を < → &lt; 置換するのが筋ではないかと。もし問題が起きるようであれば script 要素内容をいったん移動させるとか,最初から CDATA にしておくとか。

いや,XHTML じゃなくて HTML だったら何の問題もないのですが。

14   名前: sevi- : 2006/08/27(日) 08:48  ID:A5/hQl8Z
>>その場合は script 要素内容を < → &lt; 置換するのが筋ではないかと

それをやると成る程、XML文書単体としては整合性が保てるが、scriptの解釈上
としてはエラーが発生すると思うが.両者(XML&HTML)で整合性が保てないと意味がない.
(そういえば初めから無理と考え試した記憶が無いが,firefoxでは出ないのだろうか?
尚、IEでは問答無用でスクリプトエラーの筈だ.そして更に言うなら今回の話は
IE上でのselectNodes実装の話だ)

仮に<を&lt;にしたスクリプトコードを通すブラウザがあるとして、何にせよ、
ほんの少しまじないを加えるだけで遙かに編集効率が上がる事が分かり切っているのだから
使わない手はない.少なくとも必要ないなどと言うのはおかしい.

過去script要素内をコメント化したのは単にscript要素を解釈できないブラウザに対する
配慮だったと記憶しているが、HTMLとしてもxml文書としても整合性を保つ必要がある
xhtml上ではむしろ内部にスクリプトコードを記述するなら両方の整合性を保つために
必要性はより高まったと言えると思うぞ.個人的には必須と考えている.

>>最初からCDATA〜
CDATAを使うのはいかにもまずかろう.
というか少なくともIEでそれをするとスクリプトエラーになると思うのだが.
(firefoxでは検証してないがそもそもこの話はIE上で動作させる話なので意味がない)

&lt;や&gt;はマークアップ言語上では通るだろうがスクリプトエンジン上では通らない
だろうし、なにより流用、編集作業効率化の観点いずれの面から見てもマイナスだ.
折角まじない一つで他とほぼ同じ記法で実現できるものをわざわざ得意な記述
するのを推奨するのはおかしな話だ.(というかエラーだ)

まあ外部文書化すればいいだけの話だし、効率化の面から考えれば再利用が可能な
関数はそうすべきなのだろうが、コードを他人に提示し試用してもらう際には一文書
内に纏めた方が便利なのでそうしている.

何か当方の解釈に誤りがあれば指摘して頂きたい.

sevi-

15   名前: Pid : 2006/08/27(日) 08:48  ID:.vBytNbs
> ほんの少しまじないを加えるだけで遙かに編集効率が上がる

そのまじないが XML・XHTML 的に妥当でない,と申し上げているのです。少なくとも,application/xhtml+xml として読み込まれることを前提とした XHTML 1.x 文書には適用できません。そして実際,

> firefoxでは出ないのだろうか

Firefox で application/xhtml+xml で読み込んだ場合,>>10 は実行されません。

> 今回の話はIE上でのselectNodes実装の話だ

この点に関しては了解しましたが,IE の現状の実装の隙間をついているようで,不安は残ります。

まあ実際問題として,HTML を XML 整形式として解釈するときに一番ネックになるのは埋め込みスクリプトだ,というのは仰る通りです。ですから,私の >>3 の loadXML には,パース前に危険な文字をエスケープ可能にしておく,という意味が込められています(たぶん,>>2 のラブーフさんの responseText もそうかと)。


> scriptの解釈上としてはエラーが発生すると思うが.
> 仮に<を&lt;にしたスクリプトコードを通すブラウザがあるとして
> &lt;や&gt;はマークアップ言語上では通るだろうがスクリプトエンジン上では通らないだろうし

まずマークアップが解釈され,その後にスクリプトが解釈されます。つまり,スクリプトエンジンにコードが渡されるときには,すでに実体参照は展開されているはずです。マトモな XML ベースブラウザならば問題ないはずです(HTML 4.01 勧告 B.3.2,XHTML 1.0 勧告 4.8)。

16   名前: sevi- : 2006/08/27(日) 08:48  ID:A5/hQl8Z
>Firefox で application/xhtml+xml で読み込んだ場合,>>10 は実行されません。

くどいようだがFirefoxは今回提示したコードは検証していない以前に動作環境として考慮する必要性が無い.
なのでFirefoxでは動く〜動きません〜は蛇足以上の意味はない.それを根拠にするのはあまりに趣旨を外している.

>まずマークアップが解釈され,その後にスクリプトが解釈されます。つまり,スクリプトエンジンにコードが渡されるときには,すでに実体参照は展開されているはずです。
理論上はそうだが、少なくともIEの実装上ではそうなっていない.IEの普及率が最も高い現状でかつIE上での実装を前提にしているコードを前に
そのような話を持ち出すのは意味がないばかりか現実を見ていない仕様の盲信と当方は考える.

くどいようだがIEで実行できなければ当方の提示したソースには1ミリグラムの価値も無い.
そしてこのコードに限らず、世界の8割でWEB上のスクリプトを実行するのはIEである.
IEを無視して話すのは現実的ではない.

以上2点をふまえ、HTML文書内に記述されたJavascriptコードにコメントタグを付ける必要は無いという
発言は間違っていると考える.

sevi-

17   名前: sevi- : 2006/08/27(日) 08:48  ID:A5/hQl8Z
もっと簡単に言おう.
今回HTMLとしてだけでなくXML文書としても読み込みに成功して欲しいXMLパーサはMSXMLであり、
MSXMLにXML文書として通ればいいように記述できればいいのであってfirefoxのXMLパーサで通るように整合性を
合わせる必要性は無い(HTMLとして通る必要すら後述する理由上問題ない).
何よりfirefoxでの整合性を気にした結果、
MSXMLやIE上で実行されるscriptエンジン上でエラーが発生するようになっては本末転倒も甚だしい.
そういう事だ.

更に念のため<を使用しコメントタグを用いた文書を作成し、
FirefoxでHTML文書とXHTML文書として認識させて読み込ませて検証した.
成る程、確かにFirefoxではXHTML文書として認識させるとスクリプトはコメント扱いされ
動作せず、外すと動作する.また、&lt;等も正しく<として解釈して実行してくれるようだ.

が、HTML文書として読み込ませると逆に&lt;を使った箇所でスクリプトエラーが発生し、
実行が止まってしまった.普通、WEB上に発行されるxhtml文書はブラウザにHTML文書
として読み込まれる.それで動かないものを出してどうするというのだ.
くどいようだが、IE上でHTML文書としてもXML文書としても正しく解釈
し実行してくれなくては話にならない上に、firefox等他のブラウザ上では単にHTML文書
として問題なく認識、スクリプトも実行してくれればいいのであって
XHTML文書として解析,実行させるつもりがはなから無い.何ならxhtmlの名前空間を外しても構わない.
xhtmlを理解した上でHTML文書のように表示実行してくれるブラウザはそう多くない.むしろ
それでスクリプトが正しく解釈されなくなるなら外した方がいいかもしれない
(今回は別に必要ないが)

検証により確定した事項であるが,
仮に提出したコードがfirefox上でHTML文書として読み込んだ際、エラーが出る事があるの
ならそれはコメントタグのせいでなく他の理由である.

そもそもこんな検証は馬鹿げている.
全ての整合性を簡単に合わせ保守作業の効率も守るつもりならスクリプト部分を外部ファイルにすればいいだけの話だ.
前に提出した投稿で述べた理由により今回は内部に記述した訳だが,話題は初めからIE実装での話であり
IE上で動作確認でき,突き詰めれば他のブラウザ上ではselectNodes関数は無視し、スクリプトタグさえ認識
され解釈実行されれば良いのだから.

それともxhtml文書として書く上はコメントタグは外さなくてはならない、xhtml文書としてfirefoxに認識された
場合スクリプトが動かないという事を回避する為に、他のブラウザ上でHTML文書として解釈された際、
スクリプトエラーが発生するようなxhtml文書を量産すれば良いとでもいうのであろうか?

個人的にはxhtml文書はブラウザ上ではHTML文書として正しく認識されれば良く、
xmlパーサ上ではxml文書として正しく認識できれば良いと考えている.

xhtml文書をxhtml文書として正しく認識し表示実行してくれるブラウザの比率は現状知れており、
ほとんどの場合HTML文書として解釈実行されるのが現実な状況で、結果、世の大半の制作者が
HTML文書として読み込まれた際正しく実行されるよう腐心する中、そのように実装するとHTML文書
上はエラーが発生することが確認出来ているのxhtmlの仕様を厳密に守る事、他者に推奨する事に
何の益があるのか.百害あって一利なしと考える.

sevi-

18   名前: Pid : 2006/08/27(日) 08:48  ID:GN4gjesz
>>15
> そのまじないが XML・XHTML 的に妥当でない

この言い方はマズかったです。妥当ではあります。

しかし,XHTML の script 要素型の内容は #PCDATA であり,コメント区間は本当にコメントとして扱われます。したがって,sevi- さんがお書きになったコードが,(少なくとも公式には)sevi- さんが想定する動作にならない,という矛盾を,私は心配しているわけです。


>>16
> 現実を見ていない仕様の盲信と当方は考える.
> IEを無視して話すのは現実的ではない.

そういう大仰な話をしているのではなくて,XHTML を書くなら XHTML として問題が無いように書きましょうよ,と言ってるわけです。

たとえば,load するのではなく,あらかじめ responseText でソーステキストを取得しておいて,script 要素の内容を削除(たぶん使わないでしょうから)した後に loadXML する(>>2)。これなら,大した手間もなく,かつ XHTML としての機能性を損ねません。

コメント区間にこだわる理由はないわけです。

> HTML文書内に記述されたJavascriptコードにコメントタグを付ける必要は無いという発言は間違っていると考える.

コメントは「タグ」ではないのですがそれはともかく,今回のスクリプトにおいて,script 要素内容をコメントアウトしなければ正しく動作しないというのは,純粋に「sevi- さんのコードの都合」ですよね。

「間違っている」とするならば,それは sevi- さんの書いたコードと,選択なさった文書形式の相性が悪い(もっと言えば,アルゴリズムの問題)ということになりますまいか。

19   名前: Pid : 2006/08/27(日) 08:48  ID:GN4gjesz
>>17
ですから,そんな大層な話じゃないんですってば。>>18 にも書きましたけど

doc.load(document.parentWindow.location.href);


var r = new ActiveXObject ('Microsoft.XMLHTTP');
r.open ('get', d.location, false);
r.send(null);
if (r.responseText)
    doc.loadXML (r.responseText.replace (/.../gi, ''));


のように script 要素を削除すれば,コメント区間にする必要はなくない?という話。

ちょっとした工夫で解決できることなので,ここは現実云々で逃げる場面ではないです。

20   名前: sevi- : 2006/08/27(日) 08:48  ID:A5/hQl8Z
>>18
>XHTML の script 要素型の内容は #PCDATA であり,コメント区間は本当にコメントとして扱われます。

それで何の問題もない.なぜならXHTML文書としてブラウザに解釈させ実行表示させるつもりが初めから無いからである.
どのブラウザ上でもそのつもりが無い.IE他firefox等にて拡張子html又はhtmとした当該文書を普通に読み込ませた際、
HTML文書として解釈され、スクリプトが実行されるならそれでよい.念のため確認したが、拡張子をxml等にしない限り、
標準設定ではHTML文書として解釈される.

というか、MSXMLパーサにXML文書として通ればよいと何度も言っている筈だが.

誰もXHTML文書を理解実行表示できるブラウザ上で記述されたスクリプトが実行できるようにするとも言っていない.
HTML文書として読み込まれた際、実行できれば良い.そしてfirefoxはXHTML上で動くようにscriptを記述すると
HTML文書として読み込まれ実行される際、スクリプトの内容によってはエラーを吐く.コメント化すれば吐かない.
どちらを優先させればいいのかは火を見るよりも明らかだ.これはHTML文書として見た場合、firefox対応の為でもある(と、検証結果が言っている).

IE上ではXHTMLとしてもXML文書としてもHTML文書としても妥当であり
firefox上でもXML文書、HTML文書としても妥当であるという.

では何が問題だと聞くと,IEでしか実行出来ない機能を使用したスクリプトコードが記述されたXHTML文書を指し、
それはXHTML文書としてIE以外のブラウザでXHTMLとして読み込ませると(そんな状況は現状,まず無いと思うが)
コメント扱いされスクリプトが実行されなくなりますよと言う.

それに答える台詞は常に「そんな事は問題にする必要がない」である.

>今回のスクリプトにおいて,script 要素内容をコメントアウトしなければ正しく動作しないというのは,純粋に「sevi- さんのコードの都合」ですよね。

ちょっと待って欲しい.
HTML文書上で動けば問題ないというに.何故当該文書をXHTMLを解釈するブラウザ上で無理にXHTMLとして表示実行した場合を想定するのか理解に苦しむ.

更に言うならjavascriptコード上で>や<や&等を使わないという制限が一体どれ程の世のコードに影響を及ぼすのか想像出来ないのだろうか?
一体そんな制限項目がある内部スクリプトコードでどれ程の効率あるコードが書けると言うのだろうか?それは殆ど[forループを使うな]と言ってるのと
同じだと言うことに何故気づかないのだろう.そしてそれが非現実的な指摘であることに,こうして投稿する前に気づかなかったのであろうか?

(それともPid殿が記述するXHTML文書内のスクリプトコードにはforループが此まで一度も出現しないのだろうか……む、見てみたいぞ.と,興味は尽きない.
「まあ、外部参照しか普段使いませんから」という辺りが妥当……なのか?)

sevi-

21   名前: sevi- : 2006/08/27(日) 08:48  ID:A5/hQl8Z
>>19
理解してないのはそちらの方と考える.
HTML文書として読み込まれた際、スクリプトで変換作業をどう書いていようと
エラーが発生すると言っている.
エラーが発生し解釈実行されないコード上で&lt;や&gt;を変換する処理を記述せよと言っている君の言葉に
矛盾が無いかもう一度考えた方が良い.
そのようなコードはIE上でもfirefox上でもブラウザでHTML文書として読み込ませた際エラーが発生する事は
前回か前々回辺りで言った筈である.

sevi-

22   名前: sevi- : 2006/08/27(日) 08:48  ID:A5/hQl8Z
そろそろ眠らないとまずいのでこれで終わるが、

想定しているのは
・まずHTML文書として読み込まれ
・HTML文書上のスクリプトとして解釈実行され
・HTML文書上のスクリプト内でXML文書として読み込む

という流れである。なので、XHTML文書上で読み込まれても実行されるようコメントを外すと
・まずHTML文書として読み込まれ(OK)
・HTML文書上のスクリプトとして解釈実行され(NG)

ここでエラーが出てしまうと言っている.エラーがでるのは最初の初期化時なので、その内容に
どのような魔法の変換作業が記述されていても無意味だ.そしてエラーが出るのはIE含め検証
する必要性が本来なかった筈のfirefoxも含めて恐らく全てのブラウザと思われる.

無理なものは無理なので無理(というか非現実的)な事を言うなと言っている.
いい加減理解してくれる事を望んで寝ることにする.

sevi-

23   名前: Pid : 2006/08/27(日) 08:48  ID:GN4gjesz
>>22
> 無理なものは無理なので無理(というか非現実的)な事を言うなと言っている.

いやだから,無理でも非現実でも何でもない,と私は主張しています。そして,この点は「現実」云々で誤魔化すべき事項ではなく,純粋に sevi- さんのコードを改善すべき問題である,と主張しているのです。

>>21
> そのようなコードはIE上でもfirefox上でもブラウザでHTML文書として読み込ませた際エラーが発生する

いったいどんなコードをお書きになったのでしょうか。

>>20
> それともPid殿が記述するXHTML文書内のスクリプトコードにはforループが此まで一度も出現しないのだろうか……む、見てみたいぞ.と,興味は尽きない

実は私が本当に議論したかったのはこの点で,コメント区間に関しては「sevi- さんほどの方なら,すぐに修正できるだろう」と思っていたのですが。

まあ,いいや。さすがにこれ以上はスレ違いか。

24   名前: Pid : 2006/08/27(日) 08:48  ID:GN4gjesz
コメント区間に関してはとりあえず脇に置いておきます(一応,コメント区間あり・なしで動作するクロスブラウザ案をいくつか用意してあるので,不可能ではないはず)。


さて,IE の属性ノードの取り扱いに関してですが,IE は ownerElement を持っていないので厄介です。その点,>>8,>>10 で sevi- さんが selectSingleNode を使っているのは,私的には目から鱗がポロポロでした。感謝。

で,node が属性ノードの場合,node.selectSingleNode ('..') で ownerElement を取得できるかと思います。ついでに関数化してみたり(try...catch にしたのは,微妙な汎用性を求めた結果 (^^;))。

function getOwnerElement (attrNode, contextNode) {
    try {
        return attrNode.selectSingleNodes ('..');
    } catch (e) {
        var nodes = contextNode.getElementsByTagName ('*');
        var i = 0;
        
        while (nodes[i]) {
            var node = nodes[i++];
            var attrs = node.attributes;
            var j = 0;
            
            while (attrs[j])
                if (attrs[j++] == attrNode)
                    return node;
        }
        
        return null;
    }
}


ちなみに,>>9 の xpath.js ではどうやっているかと思ったら,全く同じように selectSingleNode を使ってました。え,上はパクったんだろって? いやえと。

25   名前: sevi- : 2006/08/27(日) 08:48  ID:PQukhZTw
では、そちらの意見を取り入れる前提でそちらの提示した内容より遙かに有用と思われるものを提示してみよう.


問題点を洗い出してみる.

コメント化した場合の問題点
・XHTML文書対応ブラウザにてXHTML文書として展開させた場合、スクリプト内容がコメント扱いされ実行されない.

コメント化しない場合の問題点
・XHTML文書対応ブラウザにてXHTML文書として展開させる場合を除き、スクリプト内容
(&lt;等を使用、内容をCDATAセクションノード化等)によってシンタックスエラーとなり実行されない.
・HTML文書内にスクリプトを記述する際、一部の文字列を実態参照に置き換えて記述する必要があり保守性、
HTML文書への流用不可、スクリプト部の外部参照可が不可能になる等、効率が著しく低下する.
・HTML文書をXHTML文書化したり、過去構築したスクリプトを流用する際、上記1の理由により無駄に修正コストがかかる.

……これだけ挙げただけでもコメント化しないなどというのは論外だと思うがどうか.

/*
また検証の際気づいたが、XHTML文書としてFirefoxで実行させると、HTML文書では実装されたdocument.bodyオブジェクト
やdocument.writeメソッド等が実装されない.これまでXHTML文書をXHTML文書として実行させるという経験が
無かったので知らなかったので推測するしか無いが、恐らくこれだけでなく他にも色々実装されないのだろう.(DOM部分もXMLDOMなのだろう)
つまり、XHTML文書でもHTML文書でも動作するようなコードを書くのはその辺り(両者で実装される機能の確認)事前調査が必須のようだ.
まあXHTML文書をHTML文書として動作させ、たまにXML1.0文書として読み込む事しか利用する気のない当方にはあまり興味の無い話だ
*/

さて、上記に挙げただけでも解るように、コメント化しないというのは弊害が多すぎ、とても実用に足るようなものではない.
あるとすれば、初めから当該文書がXHMTL文書として実行される事を前提にしている場合だけであろう.
HTML文書として取り扱った際弊害が発生する(特に1は致命的だ)ようなXHTML文書は当方に言わせればXHTML文書としての価値が無い.

これらを一挙に解決する手法はスクリプト部分を外部参照にし、そこで従来通りの記法をする事だというのが最適解だ.が、あくまで今回は
内部に必ず記述する事を前提として話そう.当方だったら、コメント化しないなどと言う手法は取らない.以下(文字数オーバーにより
次投稿に分割する)のようにするだろう.

26   名前: sevi- : 2006/08/27(日) 08:48  ID:PQukhZTw
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
   <title>Untitled Page</title>
   <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> 
   <script type="text/javascript">
   <!--
	 function test()
	 {
			alert('成功!');
	 }
   test();
   //-->
   </script>
	<script type="text/javascript">
		if(document.write == null)
		{
			alert("変換開始");
			var nodes_script = document.getElementsByTagName("script");
			var nodes_script_child;
			var list_script_code = new Array();
			for(var i=0; i != nodes_script.length; i++)
			{
				nodes_script_child = nodes_script[i].childNodes;
				for(var j=0; j != nodes_script_child.length; j++)
				{
					if(nodes_script_child[j].nodeType == 8)
						list_script_code.push(nodes_script_child[j].nodeValue);
				}
			}
			if(list_script_code.length != 0)
				eval(list_script_code.join("\n"));
		}
	</script>
</head>
<body onload="test();">
	<div>
		<a href="javascript:test();">CALL_TESTFUNC</a>
	</div>
</body>
</html>



いかがだろうか.そもそもコメント化した際の問題点は、XHTML文書として実行した際、スクリプト内部のコメントノードはコメントとして取り扱われ
実行されないというだけの話であった.別にコメントノード化している事により直接エラーが発生している訳ではない.
ならば話は簡単だ.コメント化されている部分を抽出し、evalで実装させてしまえばいいのである.
たったこれだけの事で、保守性を損なう事無く、これまでの記法が使える.
XHTML文書上でしか通用しない記法を使うか、これまで通りの記法を使い、XHTML文書として実行する事も想定する文書ならヘッダの最後尾に
上記scriptを記述し、evalで実装させるか.

どちらを採用すべきかは、言うまでもない.
コメント化されるというならそれを外せばいいと言う思考に至れず、記法を替え、読み込んだ文面を変換すれば〜等という考え方はおかしい.
効率を無視するなど論外だ.その技術が過去の資産を蔑ろにした上に何の益も見いださないのならそんな技術は捨てるべきだと考える.

そして個人的にはXHTML文書上、コメントノードの内容がスクリプトとして解釈されないのはそういう仕様にした方にそもそも問題があると考える.
XHTMLがHTML文書の延長であると思考するなら、これまで通用し、かつ、XML1.0記法上なんの問題もなかった仕様をあえて無効にする理由が無いからだ.

むろん、当方はXHTML文書をXHTML文書として実行させる予定は今のところ皆無なので上記のようなスクリプトには当分用はなさそうではある.

sevi-

27   名前: Pid : 2006/08/27(日) 08:48  ID:GN4gjesz
>>25
> コメント化しないというのは弊害が多すぎ、とても実用に足るようなものではない.

<script type="text/javascript">
//<!CDATA[<!--

if ('undefined' == typeof document.evaluate && typeof ActiveXObject)
    /* document.evaluate のエミュレーション実装 */

//-->]]>
</script>


と書くだけのことが,そんなに生産性を損ねるとは思えませんが。

え,これだと script 要素非対応ユーザエージェントで //<!CDATA[ ]]> が表示されてしまう?仰る通りですが,現状では検索エンジンか,古めの携帯端末くらいでしょう(後者は微妙に無視できないのですが,このスクリプトを携帯端末で動かす機会に改めて考えます)。少なくとも >>16 で sevi- さんが仰ったように,8 割以上のシェアを持つ IE で,何か問題が生じますか。

まあ,sevi- さんは IE で動くもの,私は IE で*も*動くものを作りたかった,ということなのでしょう。XML を扱うのにコメント区間化するというのは,今となっては弊害が多すぎます。「現実との擦り合せで妥協するポイント」が sevi- さんと私とでズレていた,ということでしょう(そもそも「非現実的」なら,いくら私でもこんな提案はしない)。

まあ,こちらではコメント区間あり HTML,コメント区間なし XHTML 両者で動作する修正を加えさせて頂きましたので,個人的にはかなり満足です(ホント欲しかったんだよコレ)。


> XHTML文書としてFirefoxで実行させると、HTML文書では実装されたdocument.bodyオブジェクトやdocument.writeメソッド等が実装されない

当たり前です。document.write,document.body は DOM HTML のメソッドであり,DOM HTML は DHTML 時代との互換性のためのモジュールですから(通常 document.implementation.hasFeature ('HTML', null) でチェックします)。

ルート要素の名前空間を XHTML のものにすれば,実装によっては XHTML 文書でも HTMLDocument と解釈してくれます。

28   名前: sevi- : 2006/08/27(日) 08:48  ID:A5/hQl8Z
>>27
と書くだけのことが,そんなに生産性を損ねるとは思えませんが。

うん?
最初に>>10にて
「うん?CDATAセクションを使わないならつけた方が無難だと思うが.」

と言ったつもりだが?常々感じていたのだが、君は人の話を聞いてないのかね.
それらを使わなかった理由も遙か昔の投稿で述べた筈だ.改めて繰り返せと言うのだろうか?

意味不明な反論をされても回答に困るのだが.
CDATAセクションを使うなら当然そのようなコードになるのは言うまでもない.
何を今更当たり前の事を指摘してるのだろうか.
くどいようだが、「IEでselectNodesを実装するにはどうしたらいいか」がスレッドの趣旨であり、
それに回答するコードを提出すればいいだけの筈の話に蛇足にしかならない意味のない指摘をしたのは
そちらだが?

そして君は回答をする度に「こうすればいい」という内容がコロコロ変化していくのはどういう事なのだ?
まだHTML文書扱いでスクリプトコード内に&lt;や&gt;や&amp;を使用したXHTMLを読み込んだ際、
シンタックスエラーが発生しどのようなコードで変換作業を書こうがそんなものは無意味だという私の問いに
答えて貰ってない気がするが.興味深いのでまずそれを解決できるコードとやらを提出して頂きたいのだが.

sevi-

29   名前: sevi- : 2006/08/27(日) 08:48  ID:A5/hQl8Z
くどいが、初めから提出したコードはXHTML文書として読み込まれる事を期待して書いたものではない.
HTML文書として読み込まれるのを期待しIEで動作確認して貰う事を前提にして書いたコードだ.
他のブラウザで動作するかは検証する必要が無いと判断した.

当たり前だが、スレッドの趣旨はIEでselectNodesを実装するにはどうすればいいかであり、
それ以外の配慮は質問内容からしても質問者の力量で十分自力で実装可能だろうと推測可能であるし,
実際,実装する際は自分でそのようにするだろう.

他のスレッドでも同様で、質問の内容に見合う回答が個々でなされており、質問内容がそもそもブラウザを
限定しているなら回答者が互換性を配慮したコードを提出する必要性はまったくない.
(それ以前にXHTML文書として動作する配慮の必要性を当方は感じないが)

・<や>や&を使わないコードを心がけるべきだ、事実自分はそうしている.
・コードの変換処理を使えばいい

というような趣旨の発言を君はした筈だ.であるのに、今度はCDATAセクションとスクリプトコメントと
コメントノードを使用したコードを
使えば一発で解決だと言う.いちいちそちらの回答に合わせて回答をするこちらは疲れる.
最後に提出したコードは、「変換作業をコード上で実装すればいいじゃないですか」という内容に
回答したものであって、最適解ではない.当たり前だが.

次に回答する時、前回までの話がまるでなかったかのような新しい提案を次々もってこられても困る.
くだらない揚げ足取りも同様だ.
初めから>>27のコードを提示していればかなり印象も変わり,いちいち一つ一つ回答する手間も
省けたろうに.

何にせよ、
質問内容とは外れる互換性チェック項目やXHTML文書として読み込まれた際の問題点の回避等は
質問の趣旨から外れている.初めから提出したコードにそのような用途は含まれていないのだから.
(というか、XHTML文書として読み込まれる事は拡張子をいじりでもしない限りFirefoxでも無いと
思うのだが何故XHTML文書として読み込まれた時のことを心配するのか未だ理解できない)

多少の互換性の問題、回答コードとして提出した際の質問者の当該記述部への再質問への再回答
に対する面倒臭さ、そもそも指摘された使用状況を想定していない、等の理由は多々あれど、
&lt;や&gt;を使え,CDATAセクションを使え,<や>や&を使うなという途中経過の指摘よりも
>>27の指摘はこちらの納得できる範疇だ.もうこれ以上は期待しない.
(この組み合わせなら指摘する通り問題はまあ出ないだろう)

これ以上は付き合うつもりは無い(そちらも当然そうだろうが)
君の言うとおり君と私の考え方の基本となるモノはどうもかなり違うようだ.
君と付き合うのはなんだか疲れる.そして今のところ君との議論で私が得たモノが無い.
これを見ている他者にも無い.

いい加減このスレッドの趣旨から外れた言い争いをやめにしたいのでそれに付いてのみ同意していただきたい.
他はもう同意してくれなくて良い.

sevi-

30   名前: Pid : 2006/08/27(日) 08:48  ID:J4isECb3
sevi- さんのコードをほぼ拝借しました m(_ _)m。XPathResult は定数だけ定義しています。

if ('undefined' == typeof document.evaluate)

(function () {
    XPathResult = { };
    XPathResult.ANY_TYPE                     = 0;
    XPathResult.NUMBER_TYPE                  = 1;
    XPathResult.STRING_TYPE                  = 2;
    XPathResult.BOOLEAN_TYPE                 = 3;
    XPathResult.UNORDERED_NODE_ITERATOR_TYPE = 4;
    XPathResult.ORDERED_NODE_ITERATOR_TYPE   = 5;
    XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE = 6;
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE   = 7;
    XPathResult.ANY_UNORDERED_NODE_TYPE      = 8;
    XPathResult.FIRST_ORDERED_NODE_TYPE      = 9;
    
    function IeXPathEvaluator (baseDocument) {
        this.mirrorDocument = createMirrorDocument (baseDocument);
    }
    
    IeXPathEvaluator.prototype.evaluate = function (expression, contextNode, resolver, type, result) {
        var origDoc = contextNode.ownerDocument.documentElement;
        var mirrDoc = this.mirrorDocument.documentElement;
        var mirrContext = getMirrorNode (contextNode, origDoc, mirrDoc);
        var mirrNodes = mirrContext.selectNodes (expression);
        
        var result = [ ];
        var i = 0;
        
        // 本来は type によって result の種別を変えるのだが省略
        while (mirrNodes[i])
            result.push (getMirrorNode (mirrNodes[i++], mirrContext, contextNode));
        
        return result;
    };
    
    var xe = new IeXPathEvaluator (this.document);
    
    document.evaluate = function () {
        return xe.evaluate.apply (xe, arguments);
    };
    
    return;
    
    
//______________________________________________________________________
    
    function createMirrorDocument () {
        try {
            var req = new ActiveXObject ('Microsoft.XMLHTTP');
            req.open ('get', location, false);
            req.send (null);
            
            var src = req.responseText;
            src = src.replace (/\u003C!DOCTYPE[^>]*>/i, '');
            src = src.replace (/(\u003C(?:area|base|basefont|br|col|frame|hr|img|input|link|meta|param)[^>]*)>/gi, function (s1, s2) {
                return s2 + (s2.charAt (s2.length - 1) != '/' ? ' /' : '') + '>';
            } );
            src = src.replace (/(\u003C)(script(?:[^\u003C]|\u003C+[^\u003C\/])*\u003C*)(\u003C\/script>)/gi,
                function (s1, c1, c2, c3) {
                    c2 = c2.replace (new RegExp ('\u003C', 'g'), '&lt;');
                    c2 = c2.replace (/&/g, '&amp;');
                    return c1 + c2 + c3;
                } );
            
            var doc = new ActiveXObject ('Msxml2.DOMDocument');
            doc.setProperty ('SelectionLanguage', 'XPath');
            doc.preserveWhiteSpace = false;
            doc.async = false;
            doc.loadXML (src);
            
            doc.documentElement.nodeName;
            return doc;
        } catch (e) {
            throw Error ('cannot create an XML document.');
        }
    }
    

31   名前: Pid : 2006/08/27(日) 08:48  ID:J4isECb3
    function getMirrorNode (node, contextNode, mirrorContextNode) {
        if (node.nodeType != 2 /*Node.ELEMENT_NODE*/) {
            var posData = getDocumentPosition (node, contextNode);
            var currentNode = mirrorContextNode;
            var i;
            
            while (posData.length)
                currentNode = currentNode.childNodes[ posData.pop () ];
            
            return currentNode;
            
        } else { // Node.ATTRIBUTE_NODE
                 // IE does not have Attr::ownerElement
            var ownerElement = getOwnerElement (node, contextNode);
            var posData = getDocumentPosition (ownerElement, contextNode);
            
            var currentNode = mirrorContextNode;
            var i;
            
            while (posData.length)
                currentNode = currentNode.childNodes[ posData.pop () ];
            
            return currentNode.attributes.getNamedItem (node.name);
        }
    }
    
    function getOwnerElement (attrNode, contextNode) {
        try {
            return attrNode.selectSingleNodes ('..');
        } catch (e) {
            var nodes = contextNode.getElementsByTagName ('*');
            var i = 0;
            
            while (nodes[i]) {
                var node = nodes[i++];
                var attrs = node.attributes;
                var j = 0;
                
                while (attrs[j])
                    if (attrs[j++] == attrNode)
                        return node;
            }
            
            return null;
        }
    }
    
    function getDocumentPosition (node, contextNode) {
        var result = [ ];
        var i, dummy;
        
        while (node && node != contextNode) {
            i = 0, dummy = node;
            
            while (dummy = dummy.previousSibling)
                i++;
            
            result.push (i);
            
            node = node.parentNode;
        }
        
        return result;
    }
    
} )();


バグ、おかしな点がありましたらご指摘頂ければ幸いです。

32   名前: Pid : 2006/08/27(日) 08:48  ID:J4isECb3
すみません、うっかりミス。

getDocumentPosition:
node && node != contextNode → ! (! node || node == contextNode)

全体:
& → \u0026

なおオリジナルにない制限として、loadXML を使ったために元文書が UTF-8/16 である必要があります(サーバ側で Content-Type を吐けば Shift_JIS などでも大丈夫です)。

一覧へ戻る