| 2 |
- |
1 |
// flattens an object (recursively!), similarly to Array#flatten
|
|
|
2 |
// e.g. flatten({ a: { b: { c: "hello!" } } }); // => "hello!"
|
|
|
3 |
function flatten(object) {
|
|
|
4 |
var check = _.isPlainObject(object) && _.size(object) === 1;
|
|
|
5 |
return check ? flatten(_.values(object)[0]) : object;
|
|
|
6 |
}
|
|
|
7 |
|
|
|
8 |
function XMLparse(xml) {
|
|
|
9 |
var data = {};
|
|
|
10 |
|
|
|
11 |
var isText = xml.nodeType === 3,
|
|
|
12 |
isElement = xml.nodeType === 1,
|
|
|
13 |
body = xml.textContent && xml.textContent.trim(),
|
|
|
14 |
hasChildren = xml.children && xml.children.length,
|
|
|
15 |
hasAttributes = xml.attributes && xml.attributes.length;
|
|
|
16 |
|
|
|
17 |
// if it's text just return it
|
|
|
18 |
if (isText) { return xml.nodeValue.trim(); }
|
|
|
19 |
|
|
|
20 |
// if it doesn't have any children or attributes, just return the contents
|
|
|
21 |
if (!hasChildren && !hasAttributes) { return body; }
|
|
|
22 |
|
|
|
23 |
// if it doesn't have children but _does_ have body content, we'll use that
|
|
|
24 |
if (!hasChildren && body.length) { data.text = body; }
|
|
|
25 |
|
|
|
26 |
// if it's an element with attributes, add them to data.attributes
|
|
|
27 |
if (isElement && hasAttributes) {
|
|
|
28 |
data.attributes = _.reduce(xml.attributes, function(obj, name, id) {
|
|
|
29 |
var attr = xml.attributes.item(id);
|
|
|
30 |
obj[attr.name] = attr.value;
|
|
|
31 |
return obj;
|
|
|
32 |
}, {});
|
|
|
33 |
}
|
|
|
34 |
|
|
|
35 |
// recursively call #XMLparse over children, adding results to data
|
|
|
36 |
_.each(xml.children, function(child) {
|
|
|
37 |
var name = child.nodeName;
|
|
|
38 |
|
|
|
39 |
// if we've not come across a child with this nodeType, add it as an object
|
|
|
40 |
// and return here
|
|
|
41 |
if (!_.has(data, name)) {
|
|
|
42 |
data[name] = XMLparse(child);
|
|
|
43 |
return;
|
|
|
44 |
}
|
|
|
45 |
|
|
|
46 |
// if we've encountered a second instance of the same nodeType, make our
|
|
|
47 |
// representation of it an array
|
|
|
48 |
if (!_.isArray(data[name])) { data[name] = [data[name]]; }
|
|
|
49 |
|
|
|
50 |
// and finally, append the new child
|
|
|
51 |
data[name].push(XMLparse(child));
|
|
|
52 |
});
|
|
|
53 |
|
|
|
54 |
// if we can, let's fold some attributes into the body
|
|
|
55 |
_.each(data.attributes, function(value, key) {
|
|
|
56 |
if (data[key] != null) { return; }
|
|
|
57 |
data[key] = value;
|
|
|
58 |
delete data.attributes[key];
|
|
|
59 |
});
|
|
|
60 |
|
|
|
61 |
// if data.attributes is now empty, get rid of it
|
|
|
62 |
if (_.isEmpty(data.attributes)) { delete data.attributes; }
|
|
|
63 |
|
|
|
64 |
// simplify to reduce number of final leaf nodes and return
|
|
|
65 |
return flatten(data);
|
|
|
66 |
}
|