commit extjs-2.2.1
[extjs.git] / source / data / XmlReader.js
1 /*\r
2  * Ext JS Library 2.2.1\r
3  * Copyright(c) 2006-2009, Ext JS, LLC.\r
4  * licensing@extjs.com\r
5  * \r
6  * http://extjs.com/license\r
7  */\r
8 \r
9 /**\r
10  * @class Ext.data.XmlReader\r
11  * @extends Ext.data.DataReader\r
12  * Data reader class to create an Array of {@link Ext.data.Record} objects from an XML document\r
13  * based on mappings in a provided {@link Ext.data.Record} constructor.<br><br>\r
14  * <p>\r
15  * <em>Note that in order for the browser to parse a returned XML document, the Content-Type\r
16  * header in the HTTP response must be set to "text/xml" or "application/xml".</em>\r
17  * <p>\r
18  * Example code:\r
19  * <pre><code>\r
20 var Employee = Ext.data.Record.create([\r
21    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"\r
22    {name: 'occupation'}                 // This field will use "occupation" as the mapping.\r
23 ]);\r
24 var myReader = new Ext.data.XmlReader({\r
25    totalRecords: "results", // The element which contains the total dataset size (optional)\r
26    record: "row",           // The repeated element which contains row information\r
27    id: "id"                 // The element within the row that provides an ID for the record (optional)\r
28 }, Employee);\r
29 </code></pre>\r
30  * <p>\r
31  * This would consume an XML file like this:\r
32  * <pre><code>\r
33 &lt;?xml version="1.0" encoding="UTF-8"?>\r
34 &lt;dataset>\r
35  &lt;results>2&lt;/results>\r
36  &lt;row>\r
37    &lt;id>1&lt;/id>\r
38    &lt;name>Bill&lt;/name>\r
39    &lt;occupation>Gardener&lt;/occupation>\r
40  &lt;/row>\r
41  &lt;row>\r
42    &lt;id>2&lt;/id>\r
43    &lt;name>Ben&lt;/name>\r
44    &lt;occupation>Horticulturalist&lt;/occupation>\r
45  &lt;/row>\r
46 &lt;/dataset>\r
47 </code></pre>\r
48  * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records\r
49  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being\r
50  * paged from the remote server.\r
51  * @cfg {String} record The DomQuery path to the repeated element which contains record information.\r
52  * @cfg {String} success The DomQuery path to the success attribute used by forms.\r
53  * @cfg {String} id The DomQuery path relative from the record element to the element that contains\r
54  * a record identifier value.\r
55  * @constructor\r
56  * Create a new XmlReader.\r
57  * @param {Object} meta Metadata configuration options\r
58  * @param {Object} recordType Either an Array of field definition objects as passed to\r
59  * {@link Ext.data.Record#create}, or a Record constructor object created using {@link Ext.data.Record#create}.\r
60  */\r
61 Ext.data.XmlReader = function(meta, recordType){\r
62     meta = meta || {};\r
63     Ext.data.XmlReader.superclass.constructor.call(this, meta, recordType || meta.fields);\r
64 };\r
65 Ext.extend(Ext.data.XmlReader, Ext.data.DataReader, {\r
66     /**\r
67      * This method is only used by a DataProxy which has retrieved data from a remote server.\r
68          * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected\r
69          * to contain a property called <tt>responseXML</tt> which refers to an XML document object.\r
70      * @return {Object} records A data block which is used by an {@link Ext.data.Store} as\r
71      * a cache of Ext.data.Records.\r
72      */\r
73     read : function(response){\r
74         var doc = response.responseXML;\r
75         if(!doc) {\r
76             throw {message: "XmlReader.read: XML Document not available"};\r
77         }\r
78         return this.readRecords(doc);\r
79     },\r
80 \r
81     /**\r
82      * Create a data block containing Ext.data.Records from an XML document.\r
83          * @param {Object} doc A parsed XML document.\r
84      * @return {Object} records A data block which is used by an {@link Ext.data.Store} as\r
85      * a cache of Ext.data.Records.\r
86      */\r
87     readRecords : function(doc){\r
88         /**\r
89          * After any data loads/reads, the raw XML Document is available for further custom processing.\r
90          * @type XMLDocument\r
91          */\r
92         this.xmlData = doc;\r
93         var root = doc.documentElement || doc;\r
94         var q = Ext.DomQuery;\r
95         var recordType = this.recordType, fields = recordType.prototype.fields;\r
96         var sid = this.meta.id;\r
97         var totalRecords = 0, success = true;\r
98         if(this.meta.totalRecords){\r
99             totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);\r
100         }\r
101 \r
102         if(this.meta.success){\r
103             var sv = q.selectValue(this.meta.success, root, true);\r
104             success = sv !== false && sv !== 'false';\r
105         }\r
106         var records = [];\r
107         var ns = q.select(this.meta.record, root);\r
108         for(var i = 0, len = ns.length; i < len; i++) {\r
109                 var n = ns[i];\r
110                 var values = {};\r
111                 var id = sid ? q.selectValue(sid, n) : undefined;\r
112                 for(var j = 0, jlen = fields.length; j < jlen; j++){\r
113                     var f = fields.items[j];\r
114                 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);\r
115                     v = f.convert(v, n);\r
116                     values[f.name] = v;\r
117                 }\r
118                 var record = new recordType(values, id);\r
119                 record.node = n;\r
120                 records[records.length] = record;\r
121             }\r
122 \r
123             return {\r
124                 success : success,\r
125                 records : records,\r
126                 totalRecords : totalRecords || records.length\r
127             };\r
128     }\r
129 });