Skip to content
This repository was archived by the owner on Jan 7, 2021. It is now read-only.

Commit 1f9fdc5

Browse files
authored
Merge branch 'master' into master
2 parents 1f4d89a + f2e88e5 commit 1f9fdc5

12 files changed

+179
-16
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,15 @@ var options = {
5454
sanitize: true,
5555
trim: true,
5656
arrayNotation: false
57+
alternateTextNode: false
5758
};
5859
```
5960

6061
* **object:** Returns a Javascript object instead of a JSON string
6162
* **reversible:** Makes the JSON reversible to XML (*)
6263
* **coerce:** Makes type coercion. i.e.: numbers and booleans present in attributes and element values are converted from string to its correspondent data types. Coerce can be optionally defined as an object with specific methods of coercion based on attribute name or tag name, with fallback to default coercion.
6364
* **trim:** Removes leading and trailing whitespaces as well as line terminators in element values.
64-
* **arrayNotation:** XML child nodes are always treated as arrays
65+
* **arrayNotation:** XML child nodes are always treated as arrays NB: you can specify a selective array of nodes for this to apply to instead of the whole document.
6566
* **sanitize:** Sanitizes the following characters present in element values:
6667

6768
```javascript
@@ -76,6 +77,8 @@ var chars = {
7677
"'": '''
7778
};
7879
```
80+
* **alternateTextNode:** Changes the default textNode property from $t to _t when option is set to true. Alternatively a string can be specified which will override $t to what ever the string is.
81+
7982

8083
### Options object for `toXml`
8184

lib/xml2json.js

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function startElement(name, attrs) {
2020
}
2121

2222
if (! (name in currentObject)) {
23-
if(options.arrayNotation) {
23+
if(options.arrayNotation || options.forceArrays[name]) {
2424
currentObject[name] = [attrs];
2525
} else {
2626
currentObject[name] = attrs;
@@ -51,35 +51,34 @@ function startElement(name, attrs) {
5151
}
5252

5353
function text(data) {
54-
currentObject['$t'] = (currentObject['$t'] || '') + data;
54+
currentObject[textNodeName()] = (currentObject[textNodeName()] || '') + data;
5555
}
5656

5757
function endElement(name) {
58-
if (currentObject['$t']) {
58+
if (currentObject[textNodeName()]) {
5959
if (options.trim) {
60-
currentObject['$t'] = currentObject['$t'].trim()
60+
currentObject[textNodeName()] = currentObject[textNodeName()].trim()
6161
}
6262

63-
// node-expat already reverse sanitizes it whether we like it or not
6463
//if (options.sanitize) {
65-
// currentObject['$t'] = sanitizer.sanitize(currentObject['$t'], true);
64+
// currentObject[textNodeName()] = sanitizer.sanitize(currentObject[textNodeName()], true);
6665
//}
6766

68-
currentObject['$t'] = coerce(currentObject['$t'],name);
67+
currentObject[textNodeName()] = coerce(currentObject[textNodeName()],name);
6968
}
7069

7170
if (currentElementName !== name) {
72-
delete currentObject['$t'];
71+
delete currentObject[textNodeName()];
7372
}
7473
// This should check to make sure that the name we're ending
7574
// matches the name we started on.
7675
var ancestor = ancestors.pop();
7776
if (!options.reversible) {
78-
if (('$t' in currentObject) && (Object.keys(currentObject).length == 1)) {
77+
if ((textNodeName() in currentObject) && (Object.keys(currentObject).length == 1)) {
7978
if (ancestor[name] instanceof Array) {
80-
ancestor[name].push(ancestor[name].pop()['$t']);
79+
ancestor[name].push(ancestor[name].pop()[textNodeName()]);
8180
} else {
82-
ancestor[name] = currentObject['$t'];
81+
ancestor[name] = currentObject[textNodeName()];
8382
}
8483
}
8584
}
@@ -113,6 +112,10 @@ function coerce(value,key) {
113112
return value;
114113
}
115114

115+
function textNodeName() {
116+
return options.alternateTextNode ? typeof options.alternateTextNode === 'string' ? options.alternateTextNode : '_t' : '$t'
117+
}
118+
116119

117120
/**
118121
* Parses xml to json using node-expat.
@@ -125,6 +128,10 @@ function coerce(value,key) {
125128
* characterized by the presence of the property $t.
126129
* - sanitize_values: If true, the parser escapes any element value in the xml
127130
* that has any of the following characters: <, >, (, ), #, #, &, ", '.
131+
* - alternateTextNode (boolean OR string):
132+
* If false or not specified: default of $t is used
133+
* If true, whenever $t is returned as an end point, is is substituted with _t
134+
* it String, whenever $t is returned as an end point, is is substituted with the String value (care advised)
128135
*
129136
* @return {String|Object} A String or an Object with the JSON representation
130137
* of the XML.
@@ -148,12 +155,19 @@ module.exports = function(xml, _options) {
148155
coerce: joi.alternatives([joi.boolean(), joi.object()]).default(false),
149156
sanitize: joi.boolean().default(true),
150157
trim: joi.boolean().default(true),
151-
arrayNotation: joi.boolean().default(false)
158+
arrayNotation: joi.alternatives([joi.boolean(), joi.array()]).default(false),
159+
alternateTextNode: [joi.boolean().default(false), joi.string().default(false)]
152160
};
153161
var validation = joi.validate(_options, schema);
154162
hoek.assert(validation.error === null, validation.error);
155163
options = validation.value;
156-
164+
options.forceArrays = {};
165+
if (Array.isArray(options.arrayNotation)) {
166+
options.arrayNotation.forEach(function(i) {
167+
options.forceArrays[i] = true;
168+
});
169+
options.arrayNotation = false;
170+
}
157171
if (!parser.parse(xml)) {
158172
throw new Error('There are errors in your xml file: ' + parser.getError());
159173
}
@@ -166,6 +180,6 @@ module.exports = function(xml, _options) {
166180

167181
//See: http://timelessrepo.com/json-isnt-a-javascript-subset
168182
json = json.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
169-
183+
170184
return json;
171185
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "xml2json",
3-
"version": "0.10.0",
3+
"version": "0.11.0",
44
"description": "Converts xml to json and vice-versa, using node-expat.",
55
"repository": "git://github.com/buglabs/node-xml2json.git",
66
"license": "MIT",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"unit":{"test":{"case":[{"justText":{"$t":"blah blah"}},{"attribText":{"attrib":"das","$t":"capital"}}]}}}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<unit>
2+
<test>
3+
<case>
4+
<justText>blah blah</justText>
5+
</case>
6+
<case>
7+
<attribText attrib='das'>capital
8+
</attribText>
9+
</case>
10+
</test>
11+
</unit>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"unit":{"test":{"case":[{"justText":{"_t":"blah blah"}},{"attribText":{"attrib":"das","_t":"capital"}}]}}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"unit":{"test":{"case":[{"justText":{"xx":"blah blah"}},{"attribText":{"attrib":"das","xx":"capital"}}]}}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"unit":{"test":{"case":[{"justText":{"zz":"blah blah"}},{"attribText":{"attrib":"das","zz":"capital"}},{"spaces":{"zz":"abc\nasdf\n a"}},{"type":"SANATISE","san":{"b":"Smith & Son","zz":"Alpha & Omega"}}]}}}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<unit>
2+
<test>
3+
<case>
4+
<justText>blah blah</justText>
5+
</case>
6+
<case>
7+
<attribText attrib='das'>capital
8+
</attribText>
9+
</case>
10+
<case>
11+
<spaces> abc
12+
asdf
13+
a </spaces>
14+
</case>
15+
<case type="SANATISE">
16+
<san b="Smith &amp; Son">
17+
Alpha &amp; Omega
18+
</san>
19+
</case>
20+
</test>
21+
</unit>
22+

test/fixtures/forceArray.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"json":{"id":"123b","vehicles":[{"year":"1989","annual_mileage":"18000","average_mileage":"30","alarm":"1","ownership":"Financed","make":"TOYOTA","model":"Camry","commute_days_per_week":"5","collision":"$ 500","comprehensive":"$ 500","primary_purpose":"Pleasure"},{"year":"2006","annual_mileage":"37500","average_mileage":"10","alarm":"1","ownership":"Owned","make":"CHRYSLER","model":"CROSSFIRE","commute_days_per_week":"3","collision":"$ 5000","comprehensive":"$ 500","primary_purpose":"CommuteWork"}],"drivers":[{"driver":"Bray Wyatt","birth_date":"1987-05-23","marital_status":"Single","relationship":"Self","gender":"Male","first_licensed":"18","license_status":"ValidLicense","occupation":"Unemployed","education":"HighSchoolDiploma","credit_rating":"Unsure"}]}}

0 commit comments

Comments
 (0)