plasmasphere.net -プラズマスフィア ドットネット-
Diary
ExtJS XmlReaderのcdata-sectionエスケープ対応
2011/02/06(Sun) 00:02
ExtJSのExt.data.XmlReaderですが、cdata-section の複数エスケープに対応していないみたいですね。
cdata-section のエスケープは基本以下の通りですが…
<HOGE><![CDATA[fuga]]></HOGE>
fugaをfuga]]>と入力すると、]]>をエスケープしないといけません。
<HOGE><![CDATA[fuga]]]]><![CDATA[>]]></HOGE>
※ cdata内で>とかを>とエスケープするってのは大間違いです。
ExtJSのXmlReaderですが、値の取得に Ext.DomQuery.selectValue を使っています。
selectValue が cdata-section のエスケープに対応してないですね。
selectValue : function(path, root, defaultValue){ path = path.replace(trimRe, ""); if(!valueCache[path]){ valueCache[path] = Ext.DomQuery.compile(path, "select"); } var n = valueCache[path](root), v; n = n[0] ? n[0] : n; if (typeof n.normalize == 'function') n.normalize(); v = (n && n.firstChild ? n.firstChild.nodeValue : null); return ((v === null||v === undefined||v==='') ? defaultValue : v); },
一応 n.normalize で正規化されてると思いきや、cdata-section はnormalizeしても正規処理されないようで。
cdata-sectionがエスケープされていると、エスケープされてる数だけ childNodes に文字列が分割されます。そういうDOM仕様です。
なので、nodeValue だとこの場合取れる値は「hoge]]」です。
本来ほしい値は「hoge]]>」ですので、nodeValue ではなく contentText だと正解になるんですが、残念ながらIE系は DOM のバージョンが低いので contentText には対応していません。
なんにしろXmlReaderを書き換えてあげないといけません。
Ext.override(Ext.data.XmlReader,{ createAccessor : function(){ var q = Ext.DomQuery; return function(key) { if (Ext.isFunction(key)) { return key; } switch(key) { case this.meta.totalProperty: return function(root, def){ return q.selectNumber(key, root, def); }; break; case this.meta.successProperty: return function(root, def) { var sv = q.selectValue(key, root, true); var success = sv !== false && sv !== 'false'; return success; }; break; default: return function(root, def) { var node = q.select(key, root, def), v = ''; node = node[0] ? node[0] : node; if (typeof node.normalize == 'function') node.normalize(); if(node.childNodes.length>0) { for(var i=0;i<node.childNodes[i];i++) { v += (node.childNodes[i] ? node.childNodes[i].nodeValue : ''); } } return v; }; break; } }; }() });
Ext.DomQuery.selectValue を override した方が楽なのかもしれませんが。
なんにしろこれで cdata-section のエスケープに対応できたと思います。