UNPKG

xmlrpc-rosnodejs

Version:

A pure JavaScript XML-RPC client and server. Patched fork from https://github.com/baalexander/node-xmlrpc.

203 lines (179 loc) 5.22 kB
var xmlBuilder = require('xmlbuilder') , dateFormatter = require('./date_formatter') , CustomType = require('./customtype') /** * Creates the XML for an XML-RPC method call. * * @param {String} method - The method name. * @param {Array} params - Params to pass in the call. * @param {Function} callback - function (error, xml) { ... } * - {Object|null} error - Any errors that occurred while building the XML, * otherwise null. * - {String} xml - The method call XML. */ exports.serializeMethodCall = function(method, params, encoding) { var params = params || [] var options = { version: '1.0', allowSurrogateChars: true } if (encoding) { options.encoding = encoding } var xml = xmlBuilder.create('methodCall', options) .ele('methodName') .txt(method) .up() .ele('params') params.forEach(function(param) { serializeValue(param, xml.ele('param')) }) // Includes the <?xml ...> declaration return xml.doc().toString() } /** * Creates the XML for an XML-RPC method response. * * @param {mixed} value - The value to pass in the response. * @param {Function} callback - function (error, xml) { ... } * - {Object|null} error - Any errors that occurred while building the XML, * otherwise null. * - {String} xml - The method response XML. */ exports.serializeMethodResponse = function(result) { var xml = xmlBuilder.create('methodResponse', { version: '1.0', allowSurrogateChars: true }) .ele('params') .ele('param') serializeValue(result, xml) // Includes the <?xml ...> declaration return xml.doc().toString() } exports.serializeFault = function(fault) { var xml = xmlBuilder.create('methodResponse', { version: '1.0', allowSurrogateChars: true }) .ele('fault') serializeValue(fault, xml) // Includes the <?xml ...> declaration return xml.doc().toString() } function serializeValue(value, xml) { var stack = [ { value: value, xml: xml } ] , current = null , valueNode = null , next = null while (stack.length > 0) { current = stack[stack.length - 1] if (current.index !== undefined) { // Iterating a compound next = getNextItemsFrame(current) if (next) { stack.push(next) } else { stack.pop() } } else { // we're about to add a new value (compound or simple) valueNode = current.xml.ele('value') switch(typeof current.value) { case 'boolean': appendBoolean(current.value, valueNode) stack.pop() break case 'string': appendString(current.value, valueNode) stack.pop() break case 'number': appendNumber(current.value, valueNode) stack.pop() break case 'object': if (current.value === null) { valueNode.ele('nil') stack.pop() } else if (current.value instanceof Date) { appendDatetime(current.value, valueNode) stack.pop() } else if (Buffer.isBuffer(current.value)) { appendBuffer(current.value, valueNode) stack.pop() } else if (current.value instanceof CustomType) { current.value.serialize(valueNode) stack.pop() } else { if (Array.isArray(current.value)) { current.xml = valueNode.ele('array').ele('data') } else { current.xml = valueNode.ele('struct') current.keys = Object.keys(current.value) } current.index = 0 next = getNextItemsFrame(current) if (next) { stack.push(next) } else { stack.pop() } } break default: stack.pop() break } } } } function getNextItemsFrame(frame) { var nextFrame = null if (frame.keys) { if (frame.index < frame.keys.length) { var key = frame.keys[frame.index++] , member = frame.xml.ele('member').ele('name').text(key).up() nextFrame = { value: frame.value[key] , xml: member } } } else if (frame.index < frame.value.length) { nextFrame = { value: frame.value[frame.index] , xml: frame.xml } frame.index++ } return nextFrame } function appendBoolean(value, xml) { xml.ele('boolean').txt(value ? 1 : 0) } var illegalChars = /^(?![^<&]*]]>[^<&]*)[^<&]*$/ function appendString(value, xml) { if (value.length === 0) { xml.ele('string') } else if (!illegalChars.test(value)) { xml.ele('string').d(value) } else { xml.ele('string').txt(value) } } function appendNumber(value, xml) { if (value % 1 == 0) { xml.ele('int').txt(value) } else { xml.ele('double').txt(value) } } function appendDatetime(value, xml) { xml.ele('dateTime.iso8601').txt(dateFormatter.encodeIso8601(value)) } function appendBuffer(value, xml) { xml.ele('base64').txt(value.toString('base64')) }