The source code

    /**
     * @class Ext.data.XmlReader
     * @extends Ext.data.DataReader
     * Data reader class to create an Array of {@link Ext.data.Record} objects from an XML document
     * based on mappings in a provided {@link Ext.data.Record} constructor.
     * Note: that in order for the browser to parse a returned XML document, the Content-Type
     * header in the HTTP response must be set to "text/xml" or "application/xml".
     * Example code:
     *
    var Employee = Ext.data.Record.create([
       {name: 'name', mapping: 'name'},     // "mapping" property not needed if it is the same as "name"
       {name: 'occupation'}                 // This field will use "occupation" as the mapping.
    ]);
    var myReader = new Ext.data.XmlReader({
       totalRecords: "results", // The element which contains the total dataset size (optional)
       record: "row",           // The repeated element which contains row information
       id: "id"                 // The element within the row that provides an ID for the record (optional)
    }, Employee);

     *
     * This would consume an XML file like this:
     *
    <?xml version="1.0" encoding="UTF-8"?>
    <dataset>
     <results>2</results>
     <row>
       <id>1</id>
       <name>Bill</name>
       <occupation>Gardener</occupation>
     </row>
     <row>
       <id>2</id>
       <name>Ben</name>
       <occupation>Horticulturalist</occupation>
     </row>
    </dataset>

     * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
     * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
     * paged from the remote server.
     * @cfg {String} record The DomQuery path to the repeated element which contains record information.
     * @cfg {String} success The DomQuery path to the success attribute used by forms.
     * @cfg {String} idPath The DomQuery path relative from the record element to the element that contains
     * a record identifier value.
     * @constructor
     * Create a new XmlReader.
     * @param {Object} meta Metadata configuration options
     * @param {Object} recordType Either an Array of field definition objects as passed to
     * {@link Ext.data.Record#create}, or a Record constructor object created using {@link Ext.data.Record#create}.
     */
    Ext.data.XmlReader = function(meta, recordType){
        meta = meta || {};
        Ext.data.XmlReader.superclass.constructor.call(this, meta, recordType || meta.fields);
    };
    Ext.extend(Ext.data.XmlReader, Ext.data.DataReader, {
        /**
         * This method is only used by a DataProxy which has retrieved data from a remote server.
         * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
         * to contain a property called responseXML which refers to an XML document object.
         * @return {Object} records A data block which is used by an {@link Ext.data.Store} as
         * a cache of Ext.data.Records.
         */
        read : function(response){
            var doc = response.responseXML;
            if(!doc) {
                throw {message: "XmlReader.read: XML Document not available"};
            }
            return this.readRecords(doc);
        },

        /**
         * Create a data block containing Ext.data.Records from an XML document.
         * @param {Object} doc A parsed XML document.
         * @return {Object} records A data block which is used by an {@link Ext.data.Store} as
         * a cache of Ext.data.Records.
         */
        readRecords : function(doc){
            /**
             * After any data loads/reads, the raw XML Document is available for further custom processing.
             * @type XMLDocument
             */
            this.xmlData = doc;
            var root = doc.documentElement || doc;
            var q = Ext.DomQuery;
            var recordType = this.recordType, fields = recordType.prototype.fields;
            var sid = this.meta.idPath || this.meta.id;
            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);
            for(var i = 0, len = ns.length; i < len; i++) {
                var n = ns[i];
                var values = {};
                var id = sid ? q.selectValue(sid, n) : undefined;
                for(var j = 0, jlen = fields.length; j < jlen; j++){
                    var f = fields.items[j];
                    var v = q.selectValue(Ext.value(f.mapping, f.name, true), n, f.defaultValue);
                    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
            };
        },

        // TODO: implement readResponse for XmlReader
        readResponse : Ext.emptyFn
    });