View Full Version : Complex/Nested XML data associations don't work

29 Jul 2011, 8:18 PM
Sencha Touch version tested:


only default ext-all.css

Platform tested against:

iOS 4
Safari 5.1 (7534.48.3)


Models with associations (hasMany, belongsTo) do not get populated when the source data is nested XML

Test Case:

XML Source:

<Channel inputId="0" chanFilters="" commFree="0" channelName="ABC1" sourceId="0" chanId="1002" chanNum="2" callSign="ABC1">
<Program title="Teenage Kicks" subTitle="Exodus" programFlags="4096" category="comedy" fileSize="0" seriesId="CRID://melbourne2.abc.net.au/248515" hostname="" catType="tvshow" programId="CRID://melbourne2.abc.net.au/248515e1267203" repeat="1" stars="0" endTime="2011-07-28T02:35:00" startTime="2011-07-28T02:11:00" lastModified="2011-07-28T02:11:00">
After annoying David, Milly and Max, the kids finally throw Vernon out. Bryan's missus won't let him stay at Bryan's either so Vernon ends up on the streets.
<Program title="ABC News" subTitle="" programFlags="0" category="News" fileSize="0" seriesId="CRID://melbourne2.abc.net.au/100662" hostname="" catType="tvshow" programId="CRID://melbourne2.abc.net.au/100662e2606775" repeat="0" stars="0" endTime="2011-07-28T09:30:00" startTime="2011-07-28T09:00:00" lastModified="2011-07-28T09:00:00">
The latest news, breaking news and live coverage of events as they happen from Australia's largest broadcast news network. Comprehensive coverage, original reporting, and analysis of news in Australia and around the world.


Ext.override( Ext.data.XmlReader, {
Override required to enable XmlReader to return attributes from XML data and
also to allow contents of XML node to be returned as a value
<key1 property="foo">hello there</key1>

fields: [{name: 'key1', mapping: '$self'},
{name: 'key1-property', mapping: '@property'}]

createAccessor: function() {
var selectValue = function(key, root, defaultValue){
if (key === '$self') {
var node = root;
if (node && node.firstChild) {
val = node.firstChild.nodeValue;
return Ext.isEmpty(val) ? defaultValue : val;

if( key == '#' ){
return root.tagName;
if( key.indexOf( '@' ) != -1 ){
var property = key.split( '@' )[ 1 ];
key = key.split( '@' )[ 0 ];
var val;
if( key.length ){
var node = Ext.DomQuery.selectNode(key, root);
if( node && node.firstChild ){
node = node.firstChild;
var node = root;
if( typeof( node.getAttribute ) != 'undefined' && typeof( property ) != 'undefined' ){
val = node.getAttribute( property );
val = node.nodeValue;
return Ext.isEmpty(val) ? defaultValue : val;

return function(key) {
var fn;

if (key == this.totalProperty) {
fn = function(root, defaultValue) {
var value = selectValue(key, root, defaultValue);
return parseFloat(value);

else if (key == this.successProperty) {
fn = function(root, defaultValue) {
var value = selectValue(key, root, true);
return (value !== false && value !== 'false');

else {
fn = function(root, defaultValue) {
return selectValue(key, root, defaultValue);

return fn;

idProperty: 'chanId',
fields: [
{name: 'chanId', mapping: '@chanId', type: 'integer'},
{name: 'inputId', mapping: '@inputId', type: 'integer'},
{name: 'channelName', mapping: '@channelName', type: 'string'},
{name: 'chanNum', mapping: '@chanNum', type: 'string'},
{name: 'callSign', mapping: '@callSign', type: 'string'}
hasMany: {model: 'ProgramInformation', name: 'Program'},

proxy: {
type: 'ajax',
url: 'data.xml',
reader: {
type: 'xml',
root: 'Channels',
record: 'Channel'

fields: [
{name: 'title', mapping: '@title', type: 'string'},
{name: 'subtitle', mapping: '@subTitle', type: 'string'},
{name: 'category', mapping: '@category', type: 'string'},
{name: 'startTime', mapping: '@startTime', type: 'string'},
{name: 'endTime', mapping: '@endTime', type: 'string'},
{name: 'repeat', mapping: '@repeat', type: 'boolean'},
{name: 'description', mapping: '$self', type: 'string'},
belongsTo: 'ChannelData',
proxy: {
type: 'memory',
reader: {
type: 'xml',
root: 'Channel',
record: 'Program'

channelStore = new Ext.data.Store({
model: 'ChannelData',
sorters: 'chanNum'

See this URL : http://home.tdack.com/mvc/list

Steps to reproduce the problem:

execute the load() method for the store


The result that was expected:

Store loads the nested data

The result that occurs instead:

Store does not load the nested data and throws an exception:

TypeError: 'undefined' is not an object (evaluating 'root.length') sencha-touch-debug-w-comments.js:15523
Data for parent item (Channel) is not loaded

Screenshot or Video:

Safari Web Inspection just before the exception is thrown

Debugging already done:

Lots of stepping through Ext.data.Reader.readRecords with no joy
if the hasMany{name: 'Program'} (and it's case sensitive) does not match the nested xml tag you are trying to get the data from an exception is not thrown and a Store is not created for the nested items, but the parent items are loaded. So if the hasMany{name: } property does not match the xml tag you are trying to extract the nested data from then data association doesn't seem to happen.

Possible fix:

No idea sorry.

This bug may be considered a duplicate of http://www.sencha.com/forum/showthread.php?115033-FIXED-583-nested-xml-complex-xml-cant-get-associations-to-work - That bug is marked as [FIXED] but it seems it isn't working for everyone.