PDA

View Full Version : XmlReader getting to attributes with colon in it



myj
21 Jun 2008, 4:09 PM
I am rather new to Ext-JS, and having fun with it..

I have a question about how to retrieve an XML attributes that have a colon in it.

Below is the XML snippet I am trying to read using the XmlReader


<Style>
<Name>poi</Name>
<Title>Default Styler</Title>
<Abstract/>
<LegendURL width="20" height="20">
<Format>image/png</Format>
<OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="http://192.168.1.2:8080/wms/GetLegendGraphic?VERSION=1.0.0&amp;FORMAT=image/png&amp;WIDTH=20&amp;HEIGHT=20&amp;LAYER=tiger:poi "/>
</LegendURL>
</Style>



I can get to all the elements and attributes except the ones under OnlineResource.

For example Style/LegentURL @width maps to 20
But Style/LegendURL/OnlineResource @xlink:href doesn't give me anything back..
I tried to escape the : with \ or just do @href etc etc, simply couldn't get it.

What am I missing ?

thaiat
21 Jun 2008, 4:54 PM
Hi,

I'm having the same issue.
It looks like Ext.DomQuery does not support namespace
Are you trying to select your nodes using Ext.DomQuery.select functions ?

PS : I'm working on a solution for this, i'will post as soon as it works

Cheers

thaiat
21 Jun 2008, 6:06 PM
ok it looks like i have a crossbrowser solution successfully tested in IE , FF and Safari !

Some explanations before the code:

I have redefined the following functions (select, selectValue , selectNumber, selectNode , selectNodeText) used by DomQuery and made a custom extension Ext.viz.DomQuery.
Note that selectNodeText is new and the reason comes from a different property name for accessing text node (xml) in IE (node.text) or FF (node.textContent).

Next i have extended XmlReader so that i can define a namespaceResolver in the meta property (this is because sometimes all name space are not present in the root node)
and i'm also using a property called location on each field definition so i can indicate if i want to pull the values from text node or from an attribute.

I could get rid of that property and make the selection based on the mapping xpath value but it was simpler to do that.

The only function redefined for XmlReader is readRecords

This is only a first try so code is not optimized

Now the code:



Ext.namespace("Ext.viz.DomQuery");

Ext.viz.DomQuery = {
select : function (path,root ,ns) {
try {
if(window.ActiveXObject){
return root.selectNodes(path);
}
else {
var oXpe = new XPathEvaluator();
if(ns)
var oNsResolver = ns;
else
var oNsResolver = oXpe.createNSResolver(root.ownerDocument == null ? root.documentElement : root.ownerDocument.documentElement);
var oResult = oXpe.evaluate(path, root, oNsResolver, 0, null);
var aFound = [];
var oRes;
while (oRes = oResult.iterateNext()){
aFound.push(oRes);
}
return aFound;
}
}
catch(e) {
}
},

selectValue : function (path, root , ns) {
var res = Ext.viz.DomQuery.select(path , root , ns);
if (res)
return res[0].value;
},

selectNumber : this.selectValue,

selectNode : function (path, root , ns) {
var res = Ext.viz.DomQuery.select(path , root , ns);
if (res)
return res[0];
},

selectNodeText : function (path, root , ns) {
// look for 'text' property for IE and 'textContent' for Mozilla
var res = Ext.viz.DomQuery.selectNode(path, root, ns);
if(res) {
if(window.ActiveXObject)
return res.text;
else
return res.textContent;
}
}
};


Ext.viz.XmlReader = function() {
Ext.viz.XmlReader.superclass.constructor.apply(this , arguments);
};


Ext.extend(Ext.viz.XmlReader , Ext.data.XmlReader , {

readRecords : function(doc) {
this.xmlData = doc;
var root = doc.documentElement || doc;
var q = Ext.viz.DomQuery; // INSTEAD OF DomQuery
var recordType = this.recordType, fields = recordType.prototype.fields;
var sid = this.meta.id;
var sidlocation = this.meta.idlocation;
var totalRecords = 0, success = true;
if(this.meta.totalRecords){
totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
}
if(this.meta.success){
var sv = q.selectValue(this.meta.success, root, true);
success = sv !== false && sv !== 'false';
}
var records = [];
var ns = q.select("//" + this.meta.record, root , this.meta.namespaceResolver);
for(var i = 0, len = ns.length; i < len; i++) {
var n = ns[i];
var values = {};
if(sidlocation == "attribute")
var id = sid ? q.selectValue(sid, n , this.meta.namespaceResolver) : undefined;
else if (sidlocation == "content")
var id = sid ? q.selectNodeText(sid, n , this.meta.namespaceResolver) : undefined;
for(var j = 0, jlen = fields.length; j < jlen; j++){
var f = fields.items[j];
if(f.location == "attribute")
var v = q.selectValue( (f.mapping || f.name), n, this.meta.namespaceResolver);
else if(f.location == "content")
var v = q.selectNodeText( (f.mapping || f.name), n, this.meta.namespaceResolver);
v = f.convert(v, n);
values[f.name] = v;
}
var record = new recordType(values, id);
record.node = n;
records[records.length] = record;
}

return {
success : success,
records : records,
totalRecords : totalRecords || records.length
};


}
});

// TEST CASE FROM HERE
var xmlStore = new Ext.data.Store({
proxy : new Ext.data.HttpProxy({
url : 'test.xml' // THIS IS THE XML FILE PRESENTED BELOW
}),
reader : new Ext.viz.XmlReader({
namespaceResolver : function (prefix) {
var ns = {
// If your namespace are not on the root node you have to manually indicate them here separated by commas
// otherwise leave the attribute namespaceResolver undefined
"xlink" : "http://www.w3.org/1999/xlink",
"foo" : "http://foo"
};
return ns[prefix] || null;
},
record : 'Style'
} , [
// you have to use a new attribute for each field to say if the value you need to extract is located in an attribute or in a text node
// possible values for location are 'attribute' or 'content'
{ name : 'width' , mapping : 'LegendURL/@width' , location : 'attribute' },
{ name : 'Url' , mapping : 'LegendURL/OnlineResource/@xlink:href' , location : 'attribute'} ,
{ name : 'Title' , mapping : 'Title' , location : 'content'}
])
});

var xmlGrid = new Ext.grid.GridPanel({
title : 'My Grid',
store : xmlStore,
width : 620,
height : 400,
loadMask : {
msg : "loading..."
},
columns : [{
header : 'width' , dataIndex : 'width' , width : 200
},{
header : 'Url' , dataIndex : 'Url' , width : 200
},{
header : 'Title' , dataIndex : 'Title' , width : 200
}],
renderTo : Ext.getBody()
});

xmlStore.load();

myj
23 Jun 2008, 9:48 PM
Thanks, Thaiat, I will give this a try...