diff --git a/lib/http-context.js b/lib/http-context.js
index 27ce93ee..9257a9a0 100644
--- a/lib/http-context.js
+++ b/lib/http-context.js
@@ -433,19 +433,26 @@ function toJSON(input) {
}
}
-function toXML(input) {
+function toXML(input, options) {
var xml;
+ var xmlDefaultOptions = { declaration : true };
+ var xmlOptions = util._extend(xmlDefaultOptions, options);
if (input && typeof input.toXML === 'function') {
xml = input.toXML();
} else {
- if (input) {
+ if (typeof input == 'string') {
+ // this is a hack to handle js2xmlparser throws syntax error on string
+ // wraps string from "a string" to "\"a string\""
+ input = JSON.stringify(input);
+ } else if (typeof input == 'object') {
// Trigger toJSON() conversions
input = toJSON(input);
}
if (Array.isArray(input)) {
input = { result: input };
}
- xml = js2xmlparser('response', input, {
+ xml = js2xmlparser(xmlOptions.wrapperElement || 'response', input, {
+ declaration : { include : xmlOptions.declaration },
prettyPrinting: {
indentString: ' '
},
@@ -501,13 +508,14 @@ function sendBodyJsonp(res, data) {
res.jsonp(data);
}
-function sendBodyXml(res, data) {
+function sendBodyXml(res, data, method) {
if (data === null) {
res.header('Content-Length', '7');
res.send('');
} else if (data) {
try {
- var xml = toXML(data);
+ var xmlOptions = method.returns[0].xml || {};
+ var xml = toXML(data, xmlOptions);
res.send(xml);
} catch (e) {
res.status(500).send(e + '\n' + data);
@@ -629,7 +637,7 @@ HttpContext.prototype.done = function(cb) {
res.header('Content-Type', operationResults.contentType);
}
if (dataExists) {
- operationResults.sendBody(res, data);
+ operationResults.sendBody(res, data, method);
} else {
if (res.statusCode === undefined || res.statusCode === 200) {
res.statusCode = 204;
diff --git a/test/rest.test.js b/test/rest.test.js
index d73986d6..31f83a81 100644
--- a/test/rest.test.js
+++ b/test/rest.test.js
@@ -1359,6 +1359,121 @@ describe('strong-remoting-rest', function() {
});
});
+ it('should allow customized xml root element', function(done) {
+ var method = givenSharedStaticMethod(
+ function bar(cb) {
+ cb(null, {a: 1, b: 2});
+ },
+ {
+ returns: {
+ arg: 'data', type: 'object', root: true,
+ xml: { wrapperElement: 'foo'}
+ },
+ http: { path: '/' }
+ }
+ );
+ request(app).get(method.classUrl)
+ .set('Accept', 'application/xml')
+ .set('Content-Type', 'application/json')
+ .send()
+ .expect('Content-Type', /xml/)
+ .expect(200, function(err, res) {
+ expect(res.text).to.equal(
+ '\n' +
+ '\n ' +
+ '1\n ' +
+ '2\n' +
+ '');
+ done(err, res);
+ });
+ });
+
+ it('should allow xml declaration to be disabled', function(done) {
+ var method = givenSharedStaticMethod(
+ function bar(cb) {
+ cb(null, {a: 1, b: 2});
+ },
+ {
+ returns: {
+ arg: 'data', type: 'object', root: true,
+ xml: { declaration : false }
+ },
+ http: { path: '/' }
+ }
+ );
+ request(app).get(method.classUrl)
+ .set('Accept', 'application/xml')
+ .set('Content-Type', 'application/json')
+ .send()
+ .expect('Content-Type', /xml/)
+ .expect(200, function(err, res) {
+ expect(res.text).to.equal(
+ '\n ' +
+ '1\n ' +
+ '2\n' +
+ '');
+ done(err, res);
+ });
+ });
+
+ it('should allow string results to output as xml', function(done) {
+ var method = givenSharedStaticMethod(
+ function bar(cb) {
+ var stringResult = 'a quick brown fox jumps over the lazy dog';
+ cb(null, stringResult);
+ },
+ {
+ returns: {
+ root: true,
+ xml: { wrapperElement : 'text' }
+ },
+ http: { path: '/' }
+ }
+ );
+ request(app).get(method.classUrl)
+ .set('Accept', 'application/xml')
+ .set('Content-Type', 'application/json')
+ .send()
+ .expect('Content-Type', /xml/)
+ .expect(200, function(err, res) {
+ expect(res.text).to.equal(
+ '\n' +
+ 'a quick brown fox jumps over the lazy dog' +
+ '');
+ done(err, res);
+ });
+ });
+
+ it('should handle UTF-8 & special & reserved characters', function(done) {
+ var method = givenSharedStaticMethod(
+ function bar(cb) {
+ var stringA = 'foo\xC1\xE1\u0102\u03A9asd><=$~!@#$%^&*()-_=+/.,;\'"[]{}?';
+ cb(null, {a: stringA});
+ },
+ {
+ returns: {
+ arg: 'data', type: 'object', root: true,
+ xml: { wrapperElement: false }
+ },
+ http: { path: '/' }
+ }
+ );
+ request(app).get(method.classUrl)
+ .set('Accept', 'application/xml')
+ .set('Content-Type', 'application/json')
+ .send()
+ .expect('Content-Type', /xml/)
+ .expect(200, function(err, res) {
+ expect(res).to.be.utf8;
+ expect(res.text).to.equal(
+ '\n' +
+ '\n ' +
+ 'fooÁáĂΩasd><=$~!@#$%^&*()-_=+/.,;'"[]{}?\n' +
+ '');
+ done();
+ });
+ });
+
it('should produce xml from json objects with toXML()', function(done) {
var method = givenSharedStaticMethod(
function bar(a, cb) {