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

Commit 31b6c72

Browse files
committed
alternate text node
make chnages and add test cases
1 parent 555ff88 commit 31b6c72

File tree

4 files changed

+108
-11
lines changed

4 files changed

+108
-11
lines changed

lib/xml2json.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,34 +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

6363
if (options.sanitize) {
64-
currentObject['$t'] = sanitizer.sanitize(currentObject['$t'], true);
64+
currentObject[textNodeName()] = sanitizer.sanitize(currentObject[textNodeName()], true);
6565
}
6666

67-
currentObject['$t'] = coerce(currentObject['$t'],name);
67+
currentObject[textNodeName()] = coerce(currentObject[textNodeName()],name);
6868
}
6969

7070
if (currentElementName !== name) {
71-
delete currentObject['$t'];
71+
delete currentObject[textNodeName()];
7272
}
7373
// This should check to make sure that the name we're ending
7474
// matches the name we started on.
7575
var ancestor = ancestors.pop();
7676
if (!options.reversible) {
77-
if (('$t' in currentObject) && (Object.keys(currentObject).length == 1)) {
77+
if ((textNodeName() in currentObject) && (Object.keys(currentObject).length == 1)) {
7878
if (ancestor[name] instanceof Array) {
79-
ancestor[name].push(ancestor[name].pop()['$t']);
79+
ancestor[name].push(ancestor[name].pop()[textNodeName()]);
8080
} else {
81-
ancestor[name] = currentObject['$t'];
81+
ancestor[name] = currentObject[textNodeName()];
8282
}
8383
}
8484
}
@@ -112,6 +112,10 @@ function coerce(value,key) {
112112
return value;
113113
}
114114

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

116120
/**
117121
* Parses xml to json using node-expat.
@@ -124,6 +128,10 @@ function coerce(value,key) {
124128
* characterized by the presence of the property $t.
125129
* - sanitize_values: If true, the parser escapes any element value in the xml
126130
* 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)
127135
*
128136
* @return {String|Object} A String or an Object with the JSON representation
129137
* of the XML.
@@ -147,7 +155,8 @@ module.exports = function(xml, _options) {
147155
coerce: joi.alternatives([joi.boolean(), joi.object()]).default(false),
148156
sanitize: joi.boolean().default(true),
149157
trim: joi.boolean().default(true),
150-
arrayNotation: joi.alternatives([joi.boolean(), joi.array()]).default(false)
158+
arrayNotation: joi.alternatives([joi.boolean(), joi.array()]).default(false),
159+
alternateTextNode: [joi.boolean().default(false), joi.string().default(false)]
151160
};
152161
var validation = joi.validate(_options, schema);
153162
hoek.assert(validation.error === null, validation.error);
@@ -171,6 +180,6 @@ module.exports = function(xml, _options) {
171180

172181
//See: http://timelessrepo.com/json-isnt-a-javascript-subset
173182
json = json.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
174-
183+
175184
return json;
176185
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"unit": {
3+
"test": {
4+
"case": [
5+
{
6+
"justText": { "zz": "blah blah" }
7+
},
8+
{
9+
"attribText": { "attrib": "das", "zz": "capital" }
10+
},
11+
{
12+
"spaces": { "zz": "abc\nasdf\n a" }
13+
},
14+
{
15+
"type": "SANATISE",
16+
"san": {"b": "Smith & Son", "zz": "Alpha & Omega" }
17+
}
18+
]
19+
}
20+
}
21+
}

test/fixtures/alternate-text-node.xml

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/test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,51 @@ describe('xml2json', function () {
170170
});
171171
})
172172

173+
describe('alternateTextNode', function () {
174+
175+
var file = __dirname + '/fixtures/alternate-text-node.xml';
176+
var data = fs.readFileSync(file);
177+
it('A: defaults without the option being defined', function(done) {
178+
179+
var result = parser.toJson(data, {reversible: true});
180+
expect(result.unit.test.case[0].justText['$t']).to.equal('blah blah');
181+
expect(result.unit.test.case[1].attribText['$t']).to.equal('capital');
182+
});
183+
184+
it('B: defaults with option as false', function(done) {
185+
186+
var result = parser.toJson(data, {alternateTextNode: false, reversible: true});
187+
expect(result.unit.test.case[0].justText['$t']).to.equal('blah blah');
188+
expect(result.unit.test.case[1].attribText['$t']).to.equal('capital');
189+
});
190+
191+
192+
it('C: uses alternate text node with option as true', function(done) {
193+
194+
var result = parser.toJson(data, {alternateTextNode: true, reversible: true});
195+
expect(result.unit.test.case[0].justText['_t']).to.equal('blah blah');
196+
expect(result.unit.test.case[1].attribText['_t']).to.equal('capital');
197+
});
198+
199+
it('D: overrides text node with option as "xx" string', function(done) {
200+
201+
var result = parser.toJson(data, {alternateTextNode: "xx", reversible: true});
202+
expect(result.unit.test.case[0].justText['xx']).to.equal('blah blah');
203+
expect(result.unit.test.case[1].attribText['xx']).to.equal('capital');
204+
});
205+
206+
it('E: double check sanatize and trim', function (done) {
207+
208+
var xml = internals.readFixture('alternate-text-node.xml');
209+
var result = parser.toJson(xml, {alternateTextNode: "zz", reversible: true, sanitize: true, trim: true});
210+
var json = internals.readFixture('alternate-text-node.json');
211+
212+
expect(result).to.equal(json);
213+
214+
done();
215+
});
216+
217+
})
173218
});
174219

175220

0 commit comments

Comments
 (0)