Hybrid View

  1. #1
    Sencha User
    Join Date
    Nov 2008
    Location
    Lyon, France
    Posts
    215
    Vote Rating
    5
    christophe.geiser will become famous soon enough

      0  

    Default real xpath selector

    real xpath selector


    Hi all,

    For those working with XML, this xpath extension might be useful. It is working well with Chrome and FF, not tested with IE (if somebody could confirm that this is ok with IE though, would be appreciated).

    use like :

    XML.xpath('.//item[@test = "me"]')

    or with namespace :

    XML.xpath('.//xf:item[@test = "me"]', {xf: 'http://www.w3.org/2002/xforms'})

    Along with those changes/overrides:
    Code:
    //====================
    //   overrideXmlReader
    //====================
     /*modify extract Data so as to allow an xpath selector*/
    Ext.override(Ext.data.XmlReader,
    	{  extractData: function(root) {
      	var me = this;
            var recordName = me.record,
            	selector	= me.selector;
            		
            if (!recordName) {
                Ext.Error.raise('Record is a required parameter');
            }
            if (recordName != root.nodeName) {
                root = Ext.DomQuery.select(selector ? selector : ('.//' + recordName), root);
            } else {
                root = [root];
            }
            return this.callParent([root]);
        }
    });
    
    
     Ext.DomQuery.select = document.xpath ? 
     	function(path, root, type) {
    		root = root || document;
    		if (Ext.DomQuery.isXml(root)) {return root.xpath(path)}
    		return Ext.DomQuery.jsSelect.call(this, path, root, type);
    	} 
    	: function(path, root, type) {return Ext.DomQuery.jsSelect.call(this, path, root, type)};
    It allows to use real xpath expressions in DomQuery selectors (and handle nested xml data with the use of a xpath selector fitting the structure of the data, e.g. like: './*/item' if the data looks like :
    Code:
    <root>
    	<items>
    		<item id="1">
    			<label>first item</label>
    			<items>
    				<item id="2">
    					<label>second Item (nested)</label>
    				</item>
    				<item id="3">
    					<label>third Item (nested)</label>
    				</item>
    			</items>
    		</item>
    	</items>
    </root>
    ).

    Cheers,
    C.

    Code:
    Ext.define('Ext.ux.xpath',{
    	singleton	: true,
    	ns 			: {":": "http://www.w3.org/1999/xhtml11","xsl": "http://www.w3.org/1999/XSL/Transform", "xsi": "http://www.w3.org/2001/XMLSchema-instance", "xsd": "http://www.w3.org/2001/XMLSchema", "xf": "http://www.w3.org/2002/xforms", "ev": "http://www.w3.org/2001/xml-events", "ext": "http://www.sencha.com"} 
    });
    Ext.define('Ext.ux.xpath.Xpath', {
    	expression	: '.',
    	ns 			: Ext.ux.xpath.ns, 
    	constructor: function(config){
    		var me = this;
    		Ext.apply(me,config);
    		if(!me.expression) {me.expression = '.'};
    		if(me.expression.substring(0,2) == '.[') { me.expression = 'self::node()' +me.expression.substring(1)} // bug ?? in chrome not evaluation .[@attribute]  or .[element]   
    		if(!me.ctx) {me.ctx = document}; 
    		if(!me.doc) {me.doc= me instanceof Document ? me: document};
    	},
    	evalMapping : {
    		1: 'numberValue',
    		2: 'stringValue',
    		3: 'booleanValue'
    	},
    	evaluate	: function() {
    		var temp,x,me=this;
    		 try {
    	              x=me.doc.evaluate(
    				me.expression, 
    				me.ctx, 
    				me.ns ? function(prefix) {return me.ns[prefix ? prefix : ":"] || null}
    						: me.doc.createNSResolver ? me.doc.createNSResolver(me.ctx) : null,
    				XPathResult.ANY_TYPE
    				,null);
    	            } catch (e) {
    	              	Ext.Error.raise({
    	                    parseError: e,
    	                    xpath: me,
    	                    msg: "xpath expression is invalid: " + me.expression
    	                });
    	            }
    		switch (x.resultType)
    			{case XPathResult.NUMBER_TYPE:
    			case XPathResult.STRING_TYPE:
    			case XPathResult.BOOLEAN_TYPE:
    				me.value=x[me.evalMapping[x.resultType]];
    				break;
    
    			case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
    			case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
    				me.value=[];
    				while (!!(temp=x.iterateNext())) me.value.push(temp);
    				break;
    
    			case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
    			case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
    				me.value=[];
    				for (temp=0;temp<x.snapshotLength;++temp) me.value.push(x.snapshotItem(i));
    				break;
    
    			case XPathResult.ANY_UNORDERED_NODE_TYPE:
    			case XPathResult.FIRST_ORDERED_NODE_TYPE:
    				me.value=x.singleNodeValue;
    				break;}
    		
    		return me.value
    	},
    	evaluateIE : function() {
    		var me = this;
    		me.setDocIE();
    		
    		return me.value = me.ctx.selectNodes(me.expression);
    	},
    	setDocIE : function() {
    		var x='', me = this;
    		if(me.doc instanceof HTMLDocument) {
    			me.doc = new ActiveXObject("Msxml2.DOMDocument").appendChild(me.doc.cloneNode(true));
    			Ext.apply(me.doc, {async: false, validateOnParse : false })
    		} 
    		me.doc.setProperty("SelectionLanguage", "XPath");
    		for (var ns in me.ns) {x += "xmlns" +(ns == ":"? "'": ":'") + this.ns[ns] + "' "};
    		me.doc.setProperty("SelectionNamespaces", x);
    	}
    },function() {
    	var Xp = this;
    	if(Ext.isIE){
    		Element.prototype.xpath = function(expression,ns) {return new Xp( {expression: expression , ns: ns || Xp.prototype.ns, ctx:this, doc:this.ownerDocument || this.elementDocument}).evaluateIE()}
    	} 
    	else { 
    		Node.prototype.xpath = function(expression,ns) {return new Xp( {expression: expression , ns: ns || Xp.prototype.ns, ctx:this, doc:this.ownerDocument}).evaluate()}
    	}
    });

  2. #2
    Sencha User
    Join Date
    Jul 2007
    Posts
    48
    Vote Rating
    0
    KampfCaspar is on a distinguished road

      0  

    Cool


    While not mainly interested in the UI document, I DO need selectors a lot on loaded xml documents... I wrote the following little wrapper class for xml documents with:
    • Ext.DomQuery.select* analogs
    • generic XPath method returning an iterator
    • XPath(Node|Number|String|Bool) -> returns ONE value or default value
    • XPath(Node|Number|String|Bool)s -> returns either array or object of values, object keys are extracted by a second xpath

    NB: I assume document.evalute (DOM 3 XPath) is available. If you're stuck with IE, have a look at JavaScript-XPath.

    Code:
    Ext.define( 'HPO.XML.Document', {
    	mixins: {
    		observable: 'Ext.util.Observable'
    	},
    
    	requires: [
    		'Ext.DomQuery',
    		'Ext.Ajax'
    	],
    
    	config: {
    		prefixes: null,
    		document: null,
    		request: null,
    		defaultType: XPathResult.ANY_TYPE
    	},
    
    	document_node: null,
    	resolver_func: null,
    	active_request: null,
    
    	constructor: function( config ) {
    		this.addEvents([
    			'beforeload',
    			'load',
    			'change',
    			'exception'
    		]);
    
    		config = config || {};
    		if ( config.documentElement ) {
    			config = { document: config };
    		}
    		else if ( Ext.isString(config) || config.url ) {
    			config = { request: config };
    		}
    
    		this.initConfig( config );
    		this.mixins.observable.constructor.call(this, config);
    
    		return this;
    	},
    
    	setPrefixes: function( ns ) {
    		var me = this;
    
    		this.prefixes = null;
    		if ( Ext.isFunction(ns) ) {
    			this.resolverfunc = ns;
    		}
    		else if ( Ext.isObject(ns) ) {
    			this.prefixes = ns;
    			this.resolverfunc = function( prefix ) {
    				return me.prefixes[prefix] || null;
    			};
    		}
    		else {
    			this.resolverfunc = null;
    		}
    
    		return this;
    	},
    
    	setRequest: function( request ) {
    		this.request = request;
    		if ( request ) {
    			this.load( request );
    		}
    		return this;
    	},
    
    	setDocument: function( doc ) {
    		var old = this.document;
    		this.document = doc;
    		this.document_node = doc ? doc.documentElement : null;
    		if ( doc !== null || old !== null ) {
    			this.fireEvent( 'change', this );
    		}
    		return this;
    	},
    
    	correctRequest: function( request ) {
    		if ( Ext.isString(request) ) {
    			request = { url: request };
    		}
    
    		return request;
    	},
    
    	load: function( request ) {
    		request = this.correctRequest( request );
    
    		Ext.apply( request, {
    			scope: this,
    			success: function( response, options ) {
    				this.active_request = null;
    				this.setDocument( response.responseXML );
    				this.fireEvent( 'load', this, response, options );
    			},
    			failure: function( response, options ) {
    				this.active_request = null;
    				this.document_node = null;
    				this.fireEvent( 'exception', this, response, options );
    			}
    		});
    
    		if ( this.fireEvent( 'beforeload', request, this ) !== false ) {
    			this.active_request = Ext.Ajax.request( request );
    		}
    	},
    
    	isLoading: function() {
    		return this.active_request ? Ext.Ajax.isLoading( this.active_request ) : false;
    	},
    	
    	hasContent: function() {
    		return (this.document_node != null);
    	},
    	
    	getRoot: function() {
    		return this.document_node;
    	},
    	
    	createResolver: function( node ) {
    		return this.resolverfunc ? this.resolverfunc : this.document.createNSResolver( node ? node : this.document_node );
    	},
    
    	resolveContext: function( context ) {
    		return context ? context : this.document_node;
    	},
    
    	CSS: function( selector, context ) {
    		return Ext.DomQuery.select( selector, this.resolveContext( context ) );
    	},
    
    	CSSNode: function( selector, context ) {
    		return Ext.DomQuery.selectNode( selector, this.resolveContext( context ) );
    	},
    
    	CSSValue: function( selector, context, defvalue ) {
    		return Ext.DomQuery.selectValue( selector, this.resolveContext( context ), defvalue );
    	},
    
    	CSSNumber: function( selector, context, defvalue ) {
    		return Ext.DomQuery.selectNumber( selector, this.resolveContext( context ), defvalue );
    	},
    
    	_collect: function( iter, extract, idpath ) {
    		var res,t;
    		var xexpr, xres;
    
    		if ( idpath ) {
    			res = {};
    			t = iter.iterateNext();
    			if ( t ) {
    				xexpr = t.ownerDocument.createExpression( idpath, this.createResolver( t ) );
    				do {
    					xres = xexpr.evaluate( t, XPathResult.STRING_TYPE, xres );
    					res[xres.stringValue] = extract(t);
    				}
    				while ( t = iter.iterateNext() );
    			}
    		}
    		else {
    			res = [];
    			while ( t = iter.iterateNext() ) {
    				res.push( extract(t) );
    			}
    		}
    		return res;
    	},
    
    	XPath: function( selector, context, type ) {
    		var c = this.resolveContext( context );
    
    		return this.document.evaluate( selector, c, this.createResolver( c ), type || this.defaultType, null );
    	},
    
    	XPathNode: function( selector, context ) {
    		var res = this.XPath( selector, context, XPathResult.FIRST_ORDERED_NODE_TYPE );
    		return res.singleNodeValue;
    	},
    
    	XPathNodes: function( selector, context, idpath ) {
    		return this._collect(
    			this.XPath( selector, context, XPathResult.ORDERED_ITERATOR_TYPE ),
    			function(node) { return node; },
    			idpath
    		);
    	},
    
    	XPathString: function( selector, context, defvalue ) {
    		var res = this.XPath( selector, context, XPathResult.STRING_TYPE );
    		return Ext.isEmpty(res.stringValue, true) ? defvalue : res.stringValue;
    	},
    
    	XPathStrings: function( selector, context, idpath ) {
    		return this._collect(
    			this.XPath( selector, context, XPathResult.ORDERED_ITERATOR_TYPE ),
    			function(node) { return node.textContent; },
    			idpath
    		);
    	},
    
    	XPathNumber: function( selector, context, defvalue ) {
    		var res = this.XPath( selector, context, XPathResult.NUMBER_TYPE );
    		return Ext.isEmpty( res.numberValue ) ? defvalue : res.numberValue;
    	},
    
    	XPathNumbers: function( selector, context, idpath ) {
    		return this._collect(
    			this.XPath( selector, context, XPathResult.ORDERED_ITERATOR_TYPE ),
    			function(node) { return Number(node.textContent); },
    			idpath
    		);
    	},
    
    	XPathBool: function( selector, context, defvalue ) {
    		var res = this.XPath( selector, context, XPathResult.BOOLEAN_TYPE );
    		return Ext.isEmpty( res.booleanValue ) ? defvalue : res.booleanValue;
    	},
    
    	XPathBools: function( selector, context, idpath ) {
    		return this._collect(
    			this.XPath( selector, context, XPathResult.ORDERED_ITERATOR_TYPE ),
    			function(node) { return Boolean(node.textContent); },
    			idpath
    		);
    	}
    
    });

  3. #3
    Sencha User
    Join Date
    Nov 2008
    Location
    Lyon, France
    Posts
    215
    Vote Rating
    5
    christophe.geiser will become famous soon enough

      0  

    Default


    Pretty cool
    Thanks for the IE xpath link
    Cheers
    C.

  4. #4
    Sencha User
    Join Date
    Nov 2011
    Posts
    1
    Vote Rating
    0
    frankfenghua is on a distinguished road

      0  

    Default christophe,can you post an working example of your xpath selector for rendering a xml

    christophe,can you post an working example of your xpath selector for rendering a xml


    i'm new to ExtJS, coming from a flex env. it's very hard for me to render a nested xml tree in tree panel.
    would you please post an working sample of how to use your xpath selector to render an nexted xml tree?

Thread Participants: 2

Turkiyenin en sevilen filmlerinin yer aldigi xnxx internet sitemiz olan ve porn sex tarzi bir site olan mobil porno izle sitemiz gercekten dillere destan bir durumda herkesin sevdigi bir site olarak tarihe gececege benziyor. Sitenin en belirgin ozelliklerinden birisi de Turkiyede gercekten kaliteli ve muntazam, duzenli porno izle siteleri olmamasidir. Bu yuzden iste. Ayrica en net goruntu kalitesine sahip adresinde yayinlanmaktadir. Mesela diğer sitelerimizden bahsedecek olursak, en iyi hd porno video arşivine sahip bir siteyiz. "The Best anal porn videos and slut anus, big asses movies set..." hd porno faketaxi