00001 var xmlBuilder = require('xmlbuilder')
00002 , dateFormatter = require('./date_formatter')
00003 , CustomType = require('./customtype')
00004
00005
00015 exports.serializeMethodCall = function(method, params, encoding) {
00016 var params = params || []
00017
00018 var options = { version: '1.0', allowSurrogateChars: true }
00019
00020 if (encoding) {
00021 options.encoding = encoding
00022 }
00023
00024 var xml = xmlBuilder.create('methodCall', options)
00025 .ele('methodName')
00026 .txt(method)
00027 .up()
00028 .ele('params')
00029
00030 params.forEach(function(param) {
00031 serializeValue(param, xml.ele('param'))
00032 })
00033
00034
00035 return xml.doc().toString()
00036 }
00037
00047 exports.serializeMethodResponse = function(result) {
00048 var xml = xmlBuilder.create('methodResponse', { version: '1.0', allowSurrogateChars: true })
00049 .ele('params')
00050 .ele('param')
00051
00052 serializeValue(result, xml)
00053
00054
00055 return xml.doc().toString()
00056 }
00057
00058 exports.serializeFault = function(fault) {
00059 var xml = xmlBuilder.create('methodResponse', { version: '1.0', allowSurrogateChars: true })
00060 .ele('fault')
00061
00062 serializeValue(fault, xml)
00063
00064
00065 return xml.doc().toString()
00066 }
00067
00068 function serializeValue(value, xml) {
00069 var stack = [ { value: value, xml: xml } ]
00070 , current = null
00071 , valueNode = null
00072 , next = null
00073
00074 while (stack.length > 0) {
00075 current = stack[stack.length - 1]
00076
00077 if (current.index !== undefined) {
00078
00079 next = getNextItemsFrame(current)
00080 if (next) {
00081 stack.push(next)
00082 }
00083 else {
00084 stack.pop()
00085 }
00086 }
00087 else {
00088
00089 valueNode = current.xml.ele('value')
00090 switch(typeof current.value) {
00091 case 'boolean':
00092 appendBoolean(current.value, valueNode)
00093 stack.pop()
00094 break
00095 case 'string':
00096 appendString(current.value, valueNode)
00097 stack.pop()
00098 break
00099 case 'number':
00100 appendNumber(current.value, valueNode)
00101 stack.pop()
00102 break
00103 case 'object':
00104 if (current.value === null) {
00105 valueNode.ele('nil')
00106 stack.pop()
00107 }
00108 else if (current.value instanceof Date) {
00109 appendDatetime(current.value, valueNode)
00110 stack.pop()
00111 }
00112 else if (Buffer.isBuffer(current.value)) {
00113 appendBuffer(current.value, valueNode)
00114 stack.pop()
00115 }
00116 else if (current.value instanceof CustomType) {
00117 current.value.serialize(valueNode)
00118 stack.pop()
00119 }
00120 else {
00121 if (Array.isArray(current.value)) {
00122 current.xml = valueNode.ele('array').ele('data')
00123 }
00124 else {
00125 current.xml = valueNode.ele('struct')
00126 current.keys = Object.keys(current.value)
00127 }
00128 current.index = 0
00129 next = getNextItemsFrame(current)
00130 if (next) {
00131 stack.push(next)
00132 }
00133 else {
00134 stack.pop()
00135 }
00136 }
00137 break
00138 default:
00139 stack.pop()
00140 break
00141 }
00142 }
00143 }
00144 }
00145
00146 function getNextItemsFrame(frame) {
00147 var nextFrame = null
00148
00149 if (frame.keys) {
00150 if (frame.index < frame.keys.length) {
00151 var key = frame.keys[frame.index++]
00152 , member = frame.xml.ele('member').ele('name').text(key).up()
00153 nextFrame = {
00154 value: frame.value[key]
00155 , xml: member
00156 }
00157 }
00158 }
00159 else if (frame.index < frame.value.length) {
00160 nextFrame = {
00161 value: frame.value[frame.index]
00162 , xml: frame.xml
00163 }
00164 frame.index++
00165 }
00166
00167 return nextFrame
00168 }
00169
00170 function appendBoolean(value, xml) {
00171 xml.ele('boolean').txt(value ? 1 : 0)
00172 }
00173
00174 var illegalChars = /^(?![^<&]*]]>[^<&]*)[^<&]*$/
00175 function appendString(value, xml) {
00176 if (value.length === 0) {
00177 xml.ele('string')
00178 }
00179 else if (!illegalChars.test(value)) {
00180 xml.ele('string').d(value)
00181 }
00182 else {
00183 xml.ele('string').txt(value)
00184 }
00185 }
00186
00187 function appendNumber(value, xml) {
00188 if (value % 1 == 0) {
00189 xml.ele('int').txt(value)
00190 }
00191 else {
00192 xml.ele('double').txt(value)
00193 }
00194 }
00195
00196 function appendDatetime(value, xml) {
00197 xml.ele('dateTime.iso8601').txt(dateFormatter.encodeIso8601(value))
00198 }
00199
00200 function appendBuffer(value, xml) {
00201 xml.ele('base64').txt(value.toString('base64'))
00202 }