aboutsummaryrefslogtreecommitdiff
path: root/lib/xmlreader.js
blob: 67dda3845364a5f7b751647fb383275a52c70a17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
var q = require("q");
var sax = require("sax");
var _ = require("underscore");

exports.read = read;

function read(xmlString) {
    var parser = sax.parser(true, {xmlns: true, position: false});
    
    //~ parser.onerror = function(error) {
        //~ Q.fcall(function () {
            //~ throw new Error("Can't do it");
        //~ });
    //~ };
    
    var rootElement = {children: []};
    var currentElement = rootElement;
    var stack = [];
    
    var deferred = q.defer();
    
    parser.onopentag = function(node) {
        var attributes = mapValues(node.attributes, function(attribute) {
            return attribute.value;
        });
        
        var element = new Element(node.name, attributes);
        currentElement.children.push(element);
        stack.push(currentElement);
        currentElement = element
    };
    
    parser.onclosetag = function(node) {
        currentElement = stack.pop();
    };
    
    parser.ontext = function(text) {
        if (currentElement !== rootElement) {
            currentElement.children.push({
                type: "text",
                value: text
            });
        }
    };
    
    parser.onend = function() {
        deferred.resolve({
            root: rootElement.children[0]
        });
    };
    
    parser.write(xmlString).close();
    
    return deferred.promise;
}

function mapValues(input, mapper, context) {
    return _.reduce(input, function (obj, v, k) {
        obj[k] = mapper.call(context, v, k, input);
        return obj;
    }, {}, context);
}

function Element(name, attributes) {
    this.type = "element";
    this.name = name;
    this.attributes = attributes;
    this.children = [];
}

Element.prototype.first = function(name) {
    return _.find(this.children, function(child) {
        return child.name == name;
    });
}