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内で>とかを&gt;とエスケープするってのは大間違いです。

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 のエスケープに対応できたと思います。


似てるっぽいネタ


 
© 1999- plasmasphere.net All rights reserved.