/
main.js
123 lines (106 loc) · 3.41 KB
/
main.js
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// libxmljs-easy
// =============
//
// libxmljs-easy is a Node.js module which simplifies XML traversing,
// similar to [E4X](http://en.wikipedia.org/wiki/ECMAScript_for_XML).
//
// Installation
// ------------
//
// npm install libxmljs-easy
//
var libxml = require("libxmljs");
var util = require("util");
var Proxy = require("node-proxy");
var handlerMaker = require("./handler-maker");
// Usage
// -----
//
// Use module
//
// var easy = require("libxmljs-easy");
//
// Parse XML
//
// var xml = easy.parse('<books><book name="Lord of the Rings">' +
// '<author name="J. R. R. Tolkien" />' +
// '<language>English</language>' +
// '</book></books>');
//
// Select elements from collections explicitly
//
// assert.equal(xml.book[0].$name, "Lord of the Rings");
// assert.equal(xml.book[0].author[0].$name, "J. R. R. Tolkien");
//
// Use shorthands (works well for case when there is single child element with given name)
//
// assert.equal(xml.book.$name, "Lord of the Rings");
// assert.equal(xml.book.author.$name, "J. R. R. Tolkien");
//
// Basically the idea is that you construct a path from tag names,
// which can optionally end with attribute name prefixed with "$".
//
// When index is ommited – the array of elements is matched.
// When attribute is accessed on such array, its value is concatenated string
// of attribute values for each of elements in the array.
//
// There is also original DOM element available as "$" property
// of individual converted elements.
//
// assert.equal(xml.book.language[0].$.text(), "English");
//
//
exports.parse = function(str) {
var xml = libxml.parseXmlString(str);
return convertElement(xml.root());
}
function enhanceResults(results) {
var handler = handlerMaker(results);
handler.get = function(target, name) {
if (typeof results[name] != "undefined") {
return results[name];
}
if (name[0] == "$") {
var attrName = name.slice(1);
return results.map(function(it) {
return it.$.attr(attrName) ? it.$.attr(attrName).value() : "";
}).join("");
}
return enhanceResults(
Array.prototype.concat.apply([],
results.map(function (result) {
return result.filter(function(it) {
return it.$.name() == name;
});
})
)
);
}
return Proxy.create(handler);
}
// Convert single DOM element into "easy" representation
function convertElement(elem) {
// Convert child elements recursively
var converted = elem.childNodes().map(function(it) {
if (it instanceof libxml.Element) {
return convertElement(it);
}
return it;
});
// Save DOM element object
Object.defineProperty(converted, "$", {value: elem});
var handler = handlerMaker(converted);
handler.get = function(target, name) {
if (typeof converted[name] != "undefined") {
return converted[name];
}
if (name[0] == "$") {
var attrName = name.slice(1);
return elem.attr(attrName) ? elem.attr(attrName).value() : "";
}
return enhanceResults(converted.filter(function(it) {
return it.$.name() == name;
}));
};
return Proxy.create(handler);
}