260 lines
7.9 KiB
VimL
260 lines
7.9 KiB
VimL
|
" xmlrpc
|
||
|
" Last Change: 2010-11-05
|
||
|
" Maintainer: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
||
|
" License: This file is placed in the public domain.
|
||
|
" Reference:
|
||
|
" http://tools.ietf.org/rfc/rfc3529.txt
|
||
|
|
||
|
let s:save_cpo = &cpo
|
||
|
set cpo&vim
|
||
|
|
||
|
let s:system = function(get(g:, 'webapi#system_function', 'system'))
|
||
|
|
||
|
function! webapi#xmlrpc#nil()
|
||
|
return 0
|
||
|
endfunction
|
||
|
|
||
|
function! webapi#xmlrpc#true()
|
||
|
return 1
|
||
|
endfunction
|
||
|
|
||
|
function! webapi#xmlrpc#false()
|
||
|
return 0
|
||
|
endfunction
|
||
|
|
||
|
function! s:get_childNode(node)
|
||
|
let child = a:node.childNode('value').childNode()
|
||
|
if empty(child)
|
||
|
let child = a:node.childNode('value')
|
||
|
endif
|
||
|
return child
|
||
|
endfunction
|
||
|
|
||
|
function! s:from_value(value)
|
||
|
let value = a:value
|
||
|
if value.name == 'methodResponse'
|
||
|
let param = value.childNode('params').childNodes('param')
|
||
|
if len(param) == 1
|
||
|
return s:from_value(s:get_childNode(param[0]))
|
||
|
else
|
||
|
let ret = []
|
||
|
for v in param
|
||
|
call add(ret, s:from_value(s:get_childNode(v)))
|
||
|
endfor
|
||
|
return ret
|
||
|
endif
|
||
|
elseif value.name == 'string'
|
||
|
return value.value()
|
||
|
elseif value.name == 'base64'
|
||
|
return value.value()
|
||
|
elseif value.name == 'dateTime.iso8601'
|
||
|
return value.value()
|
||
|
elseif value.name == 'boolean'
|
||
|
return 0+substitute(value.value(), "[ \n\r]", '', 'g')
|
||
|
elseif value.name == 'int'
|
||
|
return 0+substitute(value.value(), "[ \n\r]", '', 'g')
|
||
|
elseif value.name == 'i4'
|
||
|
return 0+substitute(value.value(), "[ \n\r]", '', 'g')
|
||
|
elseif value.name == 'double'
|
||
|
return str2float(substitute(value.value(), "[ \n\r]", '', 'g'))
|
||
|
elseif value.name == 'struct'
|
||
|
let ret = {}
|
||
|
for member in value.childNodes('member')
|
||
|
let ret[member.childNode('name').value()] = s:from_value(s:get_childNode(member))
|
||
|
endfor
|
||
|
return ret
|
||
|
elseif value.name == 'array'
|
||
|
let ret = []
|
||
|
for v in value.childNode('data').childNodes('value')
|
||
|
let child = v.childNode()
|
||
|
if !empty(child)
|
||
|
call add(ret, s:from_value(child))
|
||
|
else
|
||
|
call add(ret, v.value())
|
||
|
endif
|
||
|
endfor
|
||
|
return ret
|
||
|
elseif value.name == 'nil'
|
||
|
if get(g:, 'webapi#xmlrpc#allow_nil', 0) != 0
|
||
|
return function('webapi#xmlrpc#nil')
|
||
|
endif
|
||
|
return 0
|
||
|
elseif value.name == 'value'
|
||
|
return value.value()
|
||
|
else
|
||
|
throw "unknown type: ".value.name
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! s:to_value(content)
|
||
|
if type(a:content) == 4
|
||
|
if has_key(a:content, 'bits')
|
||
|
let struct = webapi#xml#createElement("struct")
|
||
|
|
||
|
let member = webapi#xml#createElement("member")
|
||
|
call add(struct.child, member)
|
||
|
let name = webapi#xml#createElement("name")
|
||
|
call add(member.child, name)
|
||
|
call name.value("name")
|
||
|
let value = webapi#xml#createElement("value")
|
||
|
call add(member.child, value)
|
||
|
call add(value.child, s:to_value(a:content["name"]))
|
||
|
|
||
|
let member = webapi#xml#createElement("member")
|
||
|
call add(struct.child, member)
|
||
|
let name = webapi#xml#createElement("name")
|
||
|
call name.value("bits")
|
||
|
call add(member.child, name)
|
||
|
let value = webapi#xml#createElement("value")
|
||
|
call add(member.child, value)
|
||
|
let base64 = webapi#xml#createElement("base64")
|
||
|
call add(value.child, base64)
|
||
|
if has_key(a:content, "bits") && len(a:content["bits"])
|
||
|
call base64.value(a:content["bits"])
|
||
|
elseif has_key(a:content, "path")
|
||
|
let quote = &shellxquote == '"' ? "'" : '"'
|
||
|
let bits = substitute(s:system("xxd -ps ".quote.a:content["path"].quote), "[ \n\r]", '', 'g')
|
||
|
call base64.value(webapi#base64#b64encodebin(bits))
|
||
|
endif
|
||
|
return struct
|
||
|
else
|
||
|
let struct = webapi#xml#createElement("struct")
|
||
|
for key in keys(a:content)
|
||
|
let member = webapi#xml#createElement("member")
|
||
|
let name = webapi#xml#createElement("name")
|
||
|
call name.value(key)
|
||
|
call add(member.child, name)
|
||
|
let value = webapi#xml#createElement("value")
|
||
|
call add(value.child, s:to_value(a:content[key]))
|
||
|
call add(member.child, value)
|
||
|
call add(struct.child, member)
|
||
|
endfor
|
||
|
return struct
|
||
|
endif
|
||
|
elseif type(a:content) == 3
|
||
|
let array = webapi#xml#createElement("array")
|
||
|
let data = webapi#xml#createElement("data")
|
||
|
for item in a:content
|
||
|
let value = webapi#xml#createElement("value")
|
||
|
call add(value.child, s:to_value(item))
|
||
|
call add(data.child, value)
|
||
|
endfor
|
||
|
call add(array.child, data)
|
||
|
return array
|
||
|
elseif type(a:content) == 2
|
||
|
if a:content == function('webapi#xmlrpc#true')
|
||
|
let true = webapi#xml#createElement("boolean")
|
||
|
call true.value('true')
|
||
|
return true
|
||
|
elseif a:content == function('webapi#xmlrpc#false')
|
||
|
let false = webapi#xml#createElement("boolean")
|
||
|
call false.value('false')
|
||
|
return false
|
||
|
else
|
||
|
return webapi#xml#createElement("nil")
|
||
|
endif
|
||
|
elseif type(a:content) <= 1 || type(a:content) == 5
|
||
|
if type(a:content) == 0
|
||
|
let int = webapi#xml#createElement("int")
|
||
|
call int.value(a:content)
|
||
|
return int
|
||
|
elseif type(a:content) == 1
|
||
|
let str = webapi#xml#createElement("string")
|
||
|
call str.value(a:content)
|
||
|
return str
|
||
|
elseif type(a:content) == 5
|
||
|
let double = webapi#xml#createElement("double")
|
||
|
call double.value(a:content)
|
||
|
return double
|
||
|
endif
|
||
|
endif
|
||
|
return {}
|
||
|
endfunction
|
||
|
|
||
|
function! s:to_fault(dom)
|
||
|
let struct = a:dom.find('struct')
|
||
|
let faultCode = ""
|
||
|
let faultString = ""
|
||
|
for member in struct.childNodes('member')
|
||
|
if member.childNode('name').value() == "faultCode"
|
||
|
let faultCode = member.childNode('value').value()
|
||
|
elseif member.childNode('name').value() == "faultString"
|
||
|
let faultString = member.childNode('value').value()
|
||
|
endif
|
||
|
endfor
|
||
|
return faultCode.":".faultString
|
||
|
endfunction
|
||
|
|
||
|
"add_node_params
|
||
|
"Add list of args on the xml tree.
|
||
|
"input: list of args
|
||
|
"output: none
|
||
|
function! s:add_node_params(args)
|
||
|
let params = webapi#xml#createElement("params")
|
||
|
for Arg in a:args
|
||
|
let param = webapi#xml#createElement("param")
|
||
|
let value = webapi#xml#createElement("value")
|
||
|
call value.value(s:to_value(Arg))
|
||
|
call add(param.child, value)
|
||
|
call add(params.child, param)
|
||
|
unlet Arg
|
||
|
endfor
|
||
|
return params
|
||
|
endfunction
|
||
|
|
||
|
function! webapi#xmlrpc#call(uri, func, args)
|
||
|
let methodCall = webapi#xml#createElement("methodCall")
|
||
|
let methodName = webapi#xml#createElement("methodName")
|
||
|
call methodName.value(a:func)
|
||
|
call add(methodCall.child, methodName)
|
||
|
if !empty(a:args)
|
||
|
call add(methodCall.child, s:add_node_params(a:args))
|
||
|
endif
|
||
|
let xml = '<?xml version="1.0" encoding="utf-8"?>'
|
||
|
let xml .= iconv(methodCall.toString(), &encoding, "utf-8")
|
||
|
let res = webapi#http#post(a:uri, xml, {"Content-Type": "text/xml"})
|
||
|
let dom = webapi#xml#parse(res.content)
|
||
|
if len(dom.find('fault'))
|
||
|
throw s:to_fault(dom)
|
||
|
else
|
||
|
return s:from_value(dom)
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! webapi#xmlrpc#wrap(contexts)
|
||
|
let api = {}
|
||
|
for context in a:contexts
|
||
|
let target = api
|
||
|
let namespaces = split(context.name, '\.')[:-2]
|
||
|
if len(namespaces) > 0
|
||
|
for ns in namespaces
|
||
|
if !has_key(target, ns)
|
||
|
let target[ns] = {".uri": context.uri}
|
||
|
endif
|
||
|
let target = target[ns]
|
||
|
let api['.uri'] = target['.uri']
|
||
|
endfor
|
||
|
endif
|
||
|
if len(context.argnames) && context.argnames[-1] == '...'
|
||
|
let arglist = '[' . join(map(copy(context.argnames[:-2]),'"a:".v:val'),',') . ']+a:000'
|
||
|
else
|
||
|
let arglist = '[' . join(map(copy(context.argnames),'"a:".v:val'),',') . ']'
|
||
|
endif
|
||
|
if has_key(context, 'alias')
|
||
|
exe "function api.".context.alias."(".join(context.argnames,",").") dict\n"
|
||
|
\. " return webapi#xmlrpc#call(self['.uri'], '".context.name."', ".arglist.")\n"
|
||
|
\. "endfunction\n"
|
||
|
else
|
||
|
exe "function api.".context.name."(".join(context.argnames,",").") dict\n"
|
||
|
\. " return webapi#xmlrpc#call('".context.uri."', '".context.name."', ".arglist.")\n"
|
||
|
\. "endfunction\n"
|
||
|
endif
|
||
|
endfor
|
||
|
return api
|
||
|
endfunction
|
||
|
|
||
|
let &cpo = s:save_cpo
|
||
|
unlet s:save_cpo
|
||
|
|
||
|
" vim:set et:
|