The previous article VMS Tech Demo 11 - XML-RPC used XML-RPC libraries. This article will format and parse XML directly.
We will use the same examples as in VMS Tech Demo 11 - XML-RPC.
XML is formatted to improve readability.
method | request | response flavor A | response flavor B |
---|---|---|---|
getInt |
|
|
|
getString |
|
|
|
getData |
|
|
|
getListOfInts |
|
|
|
getListOfStrings |
|
|
|
getListOfData |
|
|
|
add |
|
|
|
concat |
|
|
|
modify |
|
|
|
We see that:
We see that:
To keep things simple we will only do the two first groups and not the last group. It is possible to use structs using direct XML - the code will just become very messy.
We will use a simple HTTP library. Any HTTP library capable of sending POST requests should be fine. I use the same HTTP library as in previous article.
XML formatting is done by just inserting values in hardcoded XML.
XML "parsing" is done by a grab function that simply grabs everything between a start tag and an end tag.
The code should be practically identical across all languages shown.
Note that the grab function is written to be simple and easily implementable in any language. It can be optimized in most languages.
The servers are the same Java and Python servers as used in VMS Tech Demo 11 - XML-RPC.
The direct XML approach is certainly possible in these languages, but given the existence of excellent libraries also on VMS, then there is no point.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "vms_http.h"
const int NONGREEDY = 0;
const int GREEDY = 1;
static int grab(const char *xmlstr, int *start, int *end, const char *tag, int greedy)
{
char starttag[32], endtag[32];
snprintf(starttag, sizeof(starttag), "<%s>", tag);
snprintf(endtag, sizeof(endtag), "</%s>", tag);
int ixstart, ixend;
ixstart = *start;
while((ixstart < (strlen(xmlstr) - strlen(starttag))) && (memcmp(xmlstr + ixstart, starttag, strlen(starttag)) != 0)) ixstart++;
ixstart += strlen(starttag);
if(greedy)
{
ixend = *end - strlen(endtag);
while((ixend > 0) && (memcmp(xmlstr + ixend, endtag, strlen(endtag)) != 0)) ixend--;
}
else
{
ixend = ixstart;
while((ixend < (strlen(xmlstr) - strlen(starttag))) && (memcmp(xmlstr + ixend, endtag, strlen(endtag)) != 0)) ixend++;
}
if((ixstart < (strlen(xmlstr) - strlen(starttag))) && (ixend >= 0))
{
*start = ixstart;
*end = ixend;
return 1;
}
else
{
return 0;
}
}
void test(const char *host, int port)
{
printf("http://%s:%d/ (C)\n", host, port);
{
char req[1000];
snprintf(req, sizeof(req), "<methodCall><methodName>%s</methodName><params></params></methodCall>", "Test.getInt");
struct vms_http *ctx = http_post(host, port, "/", "text/xml", "text/xml", req);
char resp[10000];
short resplen;
http_recv_all(ctx, resp, sizeof(resp), &resplen);
resp[resplen] = 0;
http_close(ctx);
int ixstart = 0;
int ixend = strlen(resp) - 1;
if(grab(resp, &ixstart, &ixend, "value", GREEDY))
{
if(grab(resp, &ixstart, &ixend, "i4", GREEDY))
{
int v = atoi(resp + ixstart);
printf("%d\n", v);
}
else if(grab(resp, &ixstart, &ixend, "int", GREEDY))
{
int v = atoi(resp + ixstart);
printf("%d\n", v);
}
}
}
{
char req[1000];
snprintf(req, sizeof(req), "<methodCall><methodName>%s</methodName><params></params></methodCall>", "Test.getString");
struct vms_http *ctx = http_post(host, port, "/", "text/xml", "text/xml", req);
char resp[10000];
short resplen;
http_recv_all(ctx, resp, sizeof(resp), &resplen);
resp[resplen] = 0;
http_close(ctx);
int ixstart = 0;
int ixend = strlen(resp) - 1;
if(grab(resp, &ixstart, &ixend, "value", GREEDY))
{
if(grab(resp, &ixstart, &ixend, "string", GREEDY))
{
char s[1000];
strncpy(s, resp + ixstart, ixend - ixstart);
s[ixend - ixstart] = 0;
printf("%s\n", s);
}
else
{
char s[1000];
strncpy(s, resp + ixstart, ixend - ixstart);
s[ixend - ixstart] = 0;
printf("%s\n", s);
}
}
}
{
char req[1000];
snprintf(req, sizeof(req), "<methodCall><methodName>%s</methodName><params></params></methodCall>", "Test.getListOfInts");
struct vms_http *ctx = http_post(host, port, "/", "text/xml", "text/xml", req);
char resp[10000];
short resplen;
http_recv_all(ctx, resp, sizeof(resp), &resplen);
resp[resplen] = 0;
http_close(ctx);
int ixstart = 0;
int ixend = strlen(resp) - 1;
if(grab(resp, &ixstart, &ixend, "value", GREEDY))
{
if(grab(resp, &ixstart, &ixend, "array", GREEDY))
{
int ixstart2 = ixstart;
int ixend2 = 0;
int a[100];
int n = 0;
while(grab(resp, &ixstart2, &ixend2, "value", NONGREEDY))
{
int ixstart3 = ixstart2;
int ixend3 = ixend2;
if(grab(resp, &ixstart3, &ixend3, "i4", GREEDY))
{
a[n] = atoi(resp + ixstart3);
n++;
}
else if(grab(resp, &ixstart3, &ixend3, "int", GREEDY))
{
a[n] = atoi(resp + ixstart3);
n++;
}
ixstart2 = ixend2;
ixend2 = ixend;
}
printf("[");
for(int i = 0; i < n; i++)
{
if(i > 0) printf(",");
printf("%d", a[i]);
}
printf("]\n");
}
}
}
{
char req[1000];
snprintf(req, sizeof(req), "<methodCall><methodName>%s</methodName><params></params></methodCall>", "Test.getListOfStrings");
struct vms_http *ctx = http_post(host, port, "/", "text/xml", "text/xml", req);
char resp[10000];
short resplen;
http_recv_all(ctx, resp, sizeof(resp), &resplen);
resp[resplen] = 0;
http_close(ctx);
int ixstart = 0;
int ixend = strlen(resp) - 1;
if(grab(resp, &ixstart, &ixend, "value", GREEDY))
{
if(grab(resp, &ixstart, &ixend, "array", GREEDY))
{
int ixstart2 = ixstart;
int ixend2 = 0;
char a[100][100];
int n = 0;
while(grab(resp, &ixstart2, &ixend2, "value", NONGREEDY))
{
int ixstart3 = ixstart2;
int ixend3 = ixend2;
if(grab(resp, &ixstart3, &ixend3, "string", GREEDY))
{
strncpy(a[n], resp + ixstart3, ixend3 - ixstart3);
a[n][ixend3 - ixstart3] = 0;
n++;
}
else
{
strncpy(a[n], resp + ixstart3, ixend3 - ixstart3);
a[n][ixend3 - ixstart3] = 0;
n++;
}
ixstart2 = ixend2;
ixend2 = ixend;
}
printf("[");
for(int i = 0; i < n; i++)
{
if(i > 0) printf(",");
printf("%s", a[i]);
}
printf("]\n");
}
}
}
{
char req[1000];
int v1 = 123;
int v2 = 456;
snprintf(req, sizeof(req), "<methodCall><methodName>%s</methodName><params><param><value><i4>%d</i4></value></param><param><value><i4>%d</i4></value></param></params></methodCall>", "Test.add", v1, v2);
struct vms_http *ctx = http_post(host, port, "/", "text/xml", "text/xml", req);
char resp[10000];
short resplen;
http_recv_all(ctx, resp, sizeof(resp), &resplen);
resp[resplen] = 0;
http_close(ctx);
int ixstart = 0;
int ixend = strlen(resp) - 1;
if(grab(resp, &ixstart, &ixend, "value", GREEDY))
{
if(grab(resp, &ixstart, &ixend, "i4", GREEDY))
{
int v3 = atoi(resp + ixstart);
printf("%d\n", v3);
}
else if(grab(resp, &ixstart, &ixend, "int", GREEDY))
{
int v3 = atoi(resp + ixstart);
printf("%d\n", v3);
}
}
}
{
char req[1000];
char *s1 = "ABC";
char *s2 = "DEF";
snprintf(req, sizeof(req), "<methodCall><methodName>%s</methodName><params><param><value><string>%s</string></value></param><param><value><string>%s</string></value></param></params></methodCall>", "Test.concat", s1, s2);
struct vms_http *ctx = http_post(host, port, "/", "text/xml", "text/xml", req);
char resp[10000];
short resplen;
http_recv_all(ctx, resp, sizeof(resp), &resplen);
resp[resplen] = 0;
http_close(ctx);
int ixstart = 0;
int ixend = strlen(resp) - 1;
if(grab(resp, &ixstart, &ixend, "value", GREEDY))
{
if(grab(resp, &ixstart, &ixend, "string", GREEDY))
{
char s3[1000];
strncpy(s3, resp + ixstart, ixend - ixstart);
s3[ixend - ixstart] = 0;
printf("%s\n", s3);
}
else
{
char s3[1000];
strncpy(s3, resp + ixstart, ixend - ixstart);
s3[ixend - ixstart] = 0;
printf("%s\n", s3);
}
}
}
}
int main()
{
test("localhost", 8001);
test("localhost", 8002);
return 0;
}
$ cc/incl=xmlrpcdir diyclient
$ link diyclient + xmlrpcdir:xmlrpc/lib
$ run diyclient
We see that the C code using direct XML is more complex than the C code using libxmlrpc (as shown in XML-RPC) and C code using my homegrown library (as shown in VMS Tech Demo 11 - XML-RPC).
[inherit('pxmlrpcdir:common', 'pxmlrpcdir:phttp')]
program diyclient(input,output);
function grab(xmlstr : pstr; var xstart : integer; var xend : integer; tag : pstr; greedy : boolean) : boolean;
var
starttag, endtag : pstr;
ixstart, ixend : integer;
begin
starttag := '<' + tag + '>';
endtag := '</' + tag + '>';
ixstart := xstart;
while (ixstart < (length(xmlstr) - length(starttag))) and (substr(xmlstr, ixstart, length(starttag)) <> starttag) do ixstart := ixstart + 1;
ixstart := ixstart + length(starttag);
if(greedy) then begin
ixend := xend - length(endtag);
while (ixend > 1) and (substr(xmlstr, ixend, length(endtag)) <> endtag) do ixend := ixend - 1;
end else begin
ixend := ixstart;
while((ixend < (length(xmlstr) - length(starttag))) and (substr(xmlstr, ixend, length(endtag)) <> endtag)) do ixend := ixend + 1;
end;
if (ixstart < (length(xmlstr) - length(starttag))) and (ixend >= 1) then begin
xstart := ixstart;
xend := ixend;
grab := true;
end else begin
grab := false;
end;
end;
procedure test(host : pstr; port : integer);
procedure test_getInt(host : pstr; port : integer);
var
req, resp : pstr;
ctx : http;
ixstart, ixend, v : integer;
begin
req := '<methodCall><methodName>Test.getInt</methodName><params></params></methodCall>';
ctx := http_post(fix(host), port, '/', 'text/xml', 'text/xml', fix(req));
http_recv_all(ctx, resp.body, resp.length);
ixstart := 1;
ixend := length(resp);
if grab(resp, ixstart, ixend, 'value', true) then begin
if grab(resp, ixstart, ixend, 'i4', true) then begin
readv(substr(resp, ixstart, ixend - ixstart), v);
writeln(v:1);
end else begin
if grab(resp, ixstart, ixend, 'int', true) then begin
readv(substr(resp, ixstart, ixend - ixstart), v);
writeln(v:1);
end;
end;
end;
end;
procedure test_getString(host : pstr; port : integer);
var
req, resp, s : pstr;
ctx : http;
ixstart, ixend : integer;
begin
req := '<methodCall><methodName>Test.getString</methodName><params></params></methodCall>';
ctx := http_post(fix(host), port, '/', 'text/xml', 'text/xml', fix(req));
http_recv_all(ctx, resp.body, resp.length);
ixstart := 1;
ixend := length(resp);
if grab(resp, ixstart, ixend, 'value', true) then begin
if grab(resp, ixstart, ixend, 'string', true) then begin
s := substr(resp, ixstart, ixend - ixstart);
writeln(s);
end else begin
s := substr(resp, ixstart, ixend - ixstart);
writeln(s);
end;
end;
end;
procedure test_getListOfInts(host : pstr; port : integer);
var
req, resp : pstr;
ctx : http;
ixstart, ixend, ixstart2, ixend2, ixstart3, ixend3, n, i : integer;
a : array [1..1000] of integer;
begin
req := '<methodCall><methodName>Test.getListOfInts</methodName><params></params></methodCall>';
ctx := http_post(fix(host), port, '/', 'text/xml', 'text/xml', fix(req));
http_recv_all(ctx, resp.body, resp.length);
ixstart := 1;
ixend := length(resp);
if grab(resp, ixstart, ixend, 'value', true) then begin
if grab(resp, ixstart, ixend, 'array', true) then begin
ixstart2 := ixstart;
ixend2 := 0;
n := 0;
while grab(resp, ixstart2, ixend2, 'value', false) do begin
ixstart3 := ixstart2;
ixend3 := ixend2;
if grab(resp, ixstart3, ixend3, 'i4', true) then begin
n := n + 1;
readv(substr(resp, ixstart3, ixend3 - ixstart3), a[n]);
end else begin
if grab(resp, ixstart3, ixend3, 'int', true) then begin
n := n + 1;
readv(substr(resp, ixstart3, ixend3 - ixstart3), a[n]);
end;
end;
ixstart2 := ixend2;
ixend2 := ixend;
end;
write('[');
for i := 1 to n do begin
if i > 1 then write(',');
write(a[i]:1);
end;
writeln(']');
end;
end;
end;
procedure test_getListOfStrings(host : pstr; port : integer);
var
req, resp : pstr;
ctx : http;
ixstart, ixend, ixstart2, ixend2, ixstart3, ixend3, n, i : integer;
a : array [1..1000] of pstr;
begin
req := '<methodCall><methodName>Test.getListOfStrings</methodName><params></params></methodCall>';
ctx := http_post(fix(host), port, '/', 'text/xml', 'text/xml', fix(req));
http_recv_all(ctx, resp.body, resp.length);
ixstart := 1;
ixend := length(resp);
if grab(resp, ixstart, ixend, 'value', true) then begin
if grab(resp, ixstart, ixend, 'array', true) then begin
ixstart2 := ixstart;
ixend2 := 0;
n := 0;
while grab(resp, ixstart2, ixend2, 'value', false) do begin
ixstart3 := ixstart2;
ixend3 := ixend2;
if grab(resp, ixstart3, ixend3, 'string', true) then begin
n := n + 1;
a[n] := substr(resp, ixstart3, ixend3 - ixstart3);
end else begin
n := n + 1;
a[n] := substr(resp, ixstart3, ixend3 - ixstart3);
end;
ixstart2 := ixend2;
ixend2 := ixend;
end;
write('[');
for i := 1 to n do begin
if i > 1 then write(',');
write(a[i]);
end;
writeln(']');
end;
end;
end;
procedure test_add(host : pstr; port : integer);
var
req, resp : pstr;
ctx : http;
ixstart, ixend, v1, v2, v3 : integer;
begin
v1 := 123;
v2 := 456;
req := '<methodCall><methodName>Test.add</methodName><params><param><value><i4>' + dec(v1) + '</i4></value></param><param><value><i4>' + dec(v2) + '</i4></value></param></params></methodCall>';
ctx := http_post(fix(host), port, '/', 'text/xml', 'text/xml', fix(req));
http_recv_all(ctx, resp.body, resp.length);
ixstart := 1;
ixend := length(resp);
if grab(resp, ixstart, ixend, 'value', true) then begin
if grab(resp, ixstart, ixend, 'i4', true) then begin
readv(substr(resp, ixstart, ixend - ixstart), v3);
writeln(v3:1);
end else begin
if grab(resp, ixstart, ixend, 'int', true) then begin
readv(substr(resp, ixstart, ixend - ixstart), v3);
writeln(v3:1);
end;
end;
end;
end;
procedure test_concat(host : pstr; port : integer);
var
req, resp : pstr;
ctx : http;
ixstart, ixend : integer;
s1, s2, s3 : pstr;
begin
s1 := 'ABC';
s2 := 'DEF';
req := '<methodCall><methodName>Test.concat</methodName><params><param><value><string>' + s1 + '</string></value></param><param><value><string>' + s2 + '</string></value></param></params></methodCall>';
ctx := http_post(fix(host), port, '/', 'text/xml', 'text/xml', fix(req));
http_recv_all(ctx, resp.body, resp.length);
ixstart := 1;
ixend := length(resp);
if grab(resp, ixstart, ixend, 'value', true) then begin
if grab(resp, ixstart, ixend, 'string', true) then begin
s3 := substr(resp, ixstart, ixend - ixstart);
writeln(s3);
end else begin
s3 := substr(resp, ixstart, ixend - ixstart);
writeln(s3);
end;
end;
end;
begin
writeln('http://', host, ':', port:1, '/ (Pascal)');
test_getInt(host, port);
test_getString(host, port);
test_getListOfInts(host, port);
test_getListOfStrings(host, port);
test_add(host, port);
test_concat(host, port);
end;
begin
test('localhost', 8001);
test('localhost', 8002);
end.
$ pas diyclient
$ link diyclient + pxmlrpcdir:pxmlrpc/lib + xmlrpcdir:xmlrpc/lib
$ run diyclient
We see that the Pascal code using direct XML is more complex than the Pascal code using my homegrown library (as shown in VMS Tech Demo 11 - XML-RPC).
program diyclient
call test('localhost', 8001)
call test('localhost', 8002)
end program
c
subroutine test(host, port)
character*(*) host
integer*4 port
write(*,100) host, port
call test1(host, port)
call test2(host, port)
call test3(host, port)
call test4(host, port)
call test5(host, port)
call test6(host, port)
100 format(1x,'http://',a,':',i4,'/ (Fortran)')
end
c
subroutine test1(host, port)
character*(*) host
integer*4 port
character*1000 req, resp
integer*4 ctx, resplen, n, ixstart, ixend, v
integer*4 vms_http_post
integer*4 vms_http_recv_all
logical*4 grab
req = '<methodCall>'//
+ '<methodName>Test.getInt</methodName>'//
+ '<params></params>'//
+ '</methodCall>'
ctx = vms_http_post(host, port, '/', 'text/xml', 'text/xml', req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = resplen
if(grab(resp(1:resplen), ixstart, ixend, 'value',.true.)) then
if(grab(resp(1:resplen), ixstart, ixend, 'i4',.true.)) then
read(resp(ixstart:ixend-1), '(i)') v
write(*,*) v
else if(grab(resp(1:resplen), ixstart, ixend, 'int',.true.))then
read(resp(ixstart:ixend-1), '(i)') v
write(*,*) v
endif
endif
end
c
subroutine test2(host, port)
character*(*) host
integer*4 port
character*1000 req, resp
integer*4 ctx, resplen, n, ixstart, ixend, slen
character*100 s
integer*4 vms_http_post
integer*4 vms_http_recv_all
logical*4 grab
req = '<methodCall>'//
+ '<methodName>Test.getString</methodName>'//
+ '<params></params>'//
+ '</methodCall>'
ctx = vms_http_post(host, port, '/', 'text/xml', 'text/xml', req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = resplen
if(grab(resp(1:resplen), ixstart, ixend, 'value',.true.)) then
if(grab(resp(1:resplen), ixstart, ixend, 'string',.true.)) then
slen = ixend - ixstart
s(1:slen) = resp(ixstart:ixend-1)
write(*,*) s(1:slen)
else
slen = ixend - ixstart
s(1:slen) = resp(ixstart:ixend-1)
write(*,*) s(1:slen)
endif
endif
end
c
subroutine test3(host, port)
character*(*) host
integer*4 port
character*1000 req, resp
integer*4 ctx, resplen, n, ixstart, ixend,
+ ixstart2, ixend2, ixstart3, ixend3, i
integer*4 a(1000)
integer*4 vms_http_post
integer*4 vms_http_recv_all
logical*4 grab
req = '<methodCall>'//
+ '<methodName>Test.getListOfInts</methodName>'//
+ '<params></params>'//
+ '</methodCall>'
ctx = vms_http_post(host, port, '/', 'text/xml', 'text/xml', req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = resplen
if(grab(resp(1:resplen), ixstart, ixend, 'value', .true.)) then
if(grab(resp(1:resplen), ixstart, ixend, 'array', .true.)) then
ixstart2 = ixstart
ixend2 = 0
n = 0
100 if(grab(resp(1:resplen), ixstart2, ixend2,
+ 'value', .false.)) then
ixstart3 = ixstart2
ixend3 = ixend2
if(grab(resp(1:resplen), ixstart3, ixend3,
+ 'i4', .true.)) then
n = n + 1
read(resp(ixstart3:ixend3-1), '(i)') a(n)
else if(grab(resp(1:resplen), ixstart3, ixend3,
+ 'int', .true.)) then
n = n + 1
read(resp(ixstart3:ixend3-1), '(i)') a(n)
endif
ixstart2 = ixend2
ixend2 = ixend
goto 100
endif
write(*,'(1x,1h[,i,<n-1>(1h,,i),1h])') (a(i),i=1,n)
endif
endif
end
c
subroutine test4(host, port)
character*(*) host
integer*4 port
character*1000 req, resp
integer*4 ctx, resplen, n, ixstart, ixend, v
character*100 a(1000)
integer*4 alen(1000)
integer*4 vms_http_post
integer*4 vms_http_recv_all
logical*4 grab
req = '<methodCall>'//
+ '<methodName>Test.getListOfStrings</methodName>'//
+ '<params></params>'//
+ '</methodCall>'
ctx = vms_http_post(host, port, '/', 'text/xml', 'text/xml', req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = resplen
if(grab(resp(1:resplen), ixstart, ixend, 'value', .true.)) then
if(grab(resp(1:resplen), ixstart, ixend, 'array', .true.)) then
ixstart2 = ixstart
ixend2 = 0
n = 0
100 if(grab(resp(1:resplen), ixstart2, ixend2,
+ 'value', .false.)) then
ixstart3 = ixstart2
ixend3 = ixend2
if(grab(resp(1:resplen), ixstart3, ixend3,
+ 'string', .true.)) then
n = n + 1
alen(n) = ixend3 - ixstart3
a(n) = resp(ixstart3:ixend3-1)
else
n = n + 1
alen(n) = ixend3 - ixstart3
a(n) = resp(ixstart3:ixend3-1)
endif
ixstart2 = ixend2
ixend2 = ixend
goto 100
endif
write(*,'(1x,1h[,a,<n-1>(1h,,a),1h])') (a(i)(1:alen(i)),i=1,n)
endif
endif
end
c
subroutine test5(host, port)
character*(*) host
integer*4 port
character*1000 req, resp
integer*4 ctx, resplen, n, ixstart, ixend, v1, v2, v3
character*10 sv1, sv2
integer*4 vms_http_post
integer*4 vms_http_recv_all
logical*4 grab
v1 = 123
v2 = 456
write(sv1, '(i10)') v1
write(sv2, '(i10)') v2
req = '<methodCall>'//
+ '<methodName>Test.add</methodName>'//
+ '<params>'//
+ '<param><value><i4>'//sv1//'</i4></value></param>'//
+ '<param><value><i4>'//sv2//'</i4></value></param>'//
+ '</params>'//
+ '</methodCall>'
ctx = vms_http_post(host, port, '/', 'text/xml', 'text/xml', req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = resplen
if(grab(resp(1:resplen), ixstart, ixend, 'value',.true.)) then
if(grab(resp(1:resplen), ixstart, ixend, 'i4',.true.)) then
read(resp(ixstart:ixend-1), '(i)') v3
write(*,*) v3
else if(grab(resp(1:resplen), ixstart, ixend, 'int',.true.))then
read(resp(ixstart:ixend-1), '(i)') v3
write(*,*) v3
endif
endif
end
c
subroutine test6(host, port)
character*(*) host
integer*4 port
character*1000 req, resp
integer*4 ctx, resplen, n, ixstart, ixend, s3len
character*100 s1, s2, s3
integer*4 vms_http_post
integer*4 vms_http_recv_all
logical*4 grab
s1 = 'ABC'
s2 = 'DEF'
req = '<methodCall>'//
+ '<methodName>Test.concat</methodName>'//
+ '<params>'//
+ '<param><value><string>'//
+ trim(s1)//
+ '</string></value></param>'//
+ '<param><value><string>'//
+ trim(s2)//
+ '</string></value></param>'//
+ '</params>'//
+ '</methodCall>'
ctx = vms_http_post(host, port, '/', 'text/xml', 'text/xml', req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = resplen
if(grab(resp(1:resplen), ixstart, ixend, 'value',.true.)) then
if(grab(resp(1:resplen), ixstart, ixend, 'string',.true.)) then
s3len = ixend - ixstart
s3(1:s3len) = resp(ixstart:ixend-1)
write(*,*) s3(1:s3len)
else
s3len = ixend - ixstart
s3(1:s3len) = resp(ixstart:ixend-1)
write(*,*) s3(1:s3len)
endif
endif
end
c
logical*4 function grab(xmlstr, xstart, xend, tag, greedy)
character*(*) xmlstr, tag
integer*4 xstart, xend
logical*4 greedy
character*100 starttag, endtag
integer*4 starttaglen, endtaglen, ixstart, ixend
starttaglen = 1 + len(tag) + 1
starttag(1:starttaglen) = '<'//tag//'>'
endtaglen = 2 + len(tag) + 1
endtag(1:endtaglen) = '</'//tag//'>'
ixstart = xstart
100 if((ixstart.lt.(len(xmlstr)-starttaglen)).and.
+ (xmlstr(ixstart:ixstart+starttaglen-1).ne.
+ starttag(1:starttaglen))) then
ixstart = ixstart + 1
goto 100
endif
ixstart = ixstart + starttaglen
if(greedy) then
ixend = xend - endtaglen
200 if((ixend.gt.1).and.
+ (xmlstr(ixend:ixend+endtaglen-1).ne.endtag(1:endtaglen)))then
ixend = ixend - 1
goto 200
endif
else
ixend = ixstart
300 if((ixend.lt.(len(xmlstr)-starttaglen)).and.
+ (xmlstr(ixend:ixend+endtaglen-1).ne.endtag(1:endtaglen)))then
ixend = ixend + 1
goto 300
endif
endif
if((ixstart.lt.(len(xmlstr)-starttaglen)).and.(ixend.ge.1)) then
xstart = ixstart
xend = ixend
grab = .true.
else
grab = .false.
endif
end
$ for diyclient
$ link diyclient + pxmlrpcdir:pxmlrpc/lib + xmlrpcdir:xmlrpc/lib
$ run diyclient
We see that Fortran (77) is not a good language for XML-RPC programming. The string handling is too primitive.
program diyclient
external sub test(string, integer)
call test("localhost", 8001)
call test("localhost", 8002)
end program
!
sub test(string host, integer port)
external sub test1(string, integer)
external sub test2(string, integer)
print "http://" + host + ":" + str$(port) + "/ (Basic)"
call test1(host, port)
call test2(host, port)
call test3(host, port)
call test4(host, port)
call test5(host, port)
call test6(host, port)
end sub
!
sub test1(string host, integer port)
declare string req
map (resp) string resp = 1000
declare integer ctx, resplen, n, ixstart, ixend, v
external integer function vms_http_post(string, integer, string, string, string, string)
external integer function vms_http_recv_all(integer, string, integer)
external sub vms_http_close(integer)
external integer function grab(string, integer, integer, string, integer)
req = "<methodCall><methodName>Test.getInt</methodName><params></params></methodCall>"
ctx = vms_http_post(host, port, "/", "text/xml", "text/xml", req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = len(resp)
if grab(mid$(resp, 1, resplen), ixstart, ixend, "value", 1) <> 0 then
if grab(mid$(resp, 1, resplen), ixstart, ixend, "i4", 1) <> 0 then
v = integer(mid$(resp, ixstart, ixend - ixstart))
print v
else
if grab(mid$(resp, 1, resplen), ixstart, ixend, "int", 1) <> 0 then
v = integer(mid$(resp, ixstart, ixend - ixstart))
print v
end if
end if
end if
end sub
!
sub test2(string host, integer port)
declare string req, s
map (resp) string resp = 1000
declare integer ctx, resplen, n, ixstart, ixend
external integer function vms_http_post(string, integer, string, string, string, string)
external integer function vms_http_recv_all(integer, string, integer)
external sub vms_http_close(integer)
external integer function grab(string, integer, integer, string, integer)
req = "<methodCall><methodName>Test.getString</methodName><params></params></methodCall>"
ctx = vms_http_post(host, port, "/", "text/xml", "text/xml", req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = len(resp)
if grab(mid$(resp, 1, resplen), ixstart, ixend, "value", 1) <> 0 then
if grab(mid$(resp, 1, resplen), ixstart, ixend, "string", 1) <> 0 then
s = mid$(resp, ixstart, ixend - ixstart)
print s
else
s = mid$(resp, ixstart, ixend - ixstart)
print s
end if
end if
end sub
!
sub test3(string host, integer port)
declare string req, prtlin
map (resp) string resp = 1000
declare integer ctx, resplen, n, ixstart, ixend, ixstart2, ixend2, ixstart3, ixend3
declare integer a(1000)
external integer function vms_http_post(string, integer, string, string, string, string)
external integer function vms_http_recv_all(integer, string, integer)
external sub vms_http_close(integer)
external integer function grab(string, integer, integer, string, integer)
req = "<methodCall><methodName>Test.getListOfInts</methodName><params></params></methodCall>"
ctx = vms_http_post(host, port, "/", "text/xml", "text/xml", req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = len(resp)
if grab(mid$(resp, 1, resplen), ixstart, ixend, "value", 1) then
if grab(mid$(resp, 1, resplen), ixstart, ixend, "array", 1) then
ixstart2 = ixstart
ixend2 = 0
n = 0
while grab(mid$(resp, 1, resplen), ixstart2, ixend2, "value", 0)
ixstart3 = ixstart2
ixend3 = ixend2
if grab(mid$(resp, 1, resplen), ixstart3, ixend3, "i4", 1) then
n = n + 1
a(n) = integer(mid$(resp, ixstart3, ixend3 - ixstart3))
else
if grab(mid$(resp, 1, resplen), ixstart3, ixend3, "int", 1) then
n = n + 1
a(n) = integer(mid$(resp, ixstart3, ixend3 - ixstart3))
end if
end if
ixstart2 = ixend2
ixend2 = ixend
next
prtlin = "["
for i = 1 to n
if i > 1 then
prtlin = prtlin + ","
end if
prtlin = prtlin + str$(a(i))
next i
prtlin = prtlin + "]"
print prtlin
end if
end if
end sub
!
sub test4(string host, integer port)
declare string req, prtlin
map (resp) string resp = 1000
declare integer ctx, resplen, n, ixstart, ixend, ixstart2, ixend2, ixstart3, ixend3
declare string a(1000)
external integer function vms_http_post(string, integer, string, string, string, string)
external integer function vms_http_recv_all(integer, string, integer)
external sub vms_http_close(integer)
external integer function grab(string, integer, integer, string, integer)
req = "<methodCall><methodName>Test.getListOfStrings</methodName><params></params></methodCall>"
ctx = vms_http_post(host, port, "/", "text/xml", "text/xml", req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = len(resp)
if grab(mid$(resp, 1, resplen), ixstart, ixend, "value", 1) then
if grab(mid$(resp, 1, resplen), ixstart, ixend, "array", 1) then
ixstart2 = ixstart
ixend2 = 0
n = 0
while grab(mid$(resp, 1, resplen), ixstart2, ixend2, "value", 0)
ixstart3 = ixstart2
ixend3 = ixend2
if grab(mid$(resp, 1, resplen), ixstart3, ixend3, "string", 1) then
n = n + 1
a(n) = mid$(resp, ixstart3, ixend3 - ixstart3)
else
n = n + 1
a(n) = mid$(resp, ixstart3, ixend3 - ixstart3)
end if
ixstart2 = ixend2
ixend2 = ixend
next
prtlin = "["
for i = 1 to n
if i > 1 then
prtlin = prtlin + ","
end if
prtlin = prtlin + a(i)
next i
prtlin = prtlin + "]"
print prtlin
end if
end if
end sub
!
sub test5(string host, integer port)
declare string req
map (resp) string resp = 1000
declare integer ctx, resplen, n, ixstart, ixend, v1, v2, v3
external integer function vms_http_post(string, integer, string, string, string, string)
external integer function vms_http_recv_all(integer, string, integer)
external sub vms_http_close(integer)
external integer function grab(string, integer, integer, string, integer)
v1 = 123
v2 = 456
req = "<methodCall><methodName>Test.add</methodName><params><param><value><i4>" + str$(v1) + "</i4></value></param><param><value><i4>" + str$(v2) + "</i4></value></param></params></methodCall>"
ctx = vms_http_post(host, port, "/", "text/xml", "text/xml", req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = len(resp)
if grab(mid$(resp, 1, resplen), ixstart, ixend, "value", 1) <> 0 then
if grab(mid$(resp, 1, resplen), ixstart, ixend, "i4", 1) <> 0 then
v3 = integer(mid$(resp, ixstart, ixend - ixstart))
print v3
else
if grab(mid$(resp, 1, resplen), ixstart, ixend, "int", 1) <> 0 then
v3 = integer(mid$(resp, ixstart, ixend - ixstart))
print v3
end if
end if
end if
end sub
!
sub test6(string host, integer port)
declare string req, s1, s2, s3
map (resp) string resp = 1000
declare integer ctx, resplen, n, ixstart, ixend
external integer function vms_http_post(string, integer, string, string, string, string)
external integer function vms_http_recv_all(integer, string, integer)
external sub vms_http_close(integer)
external integer function grab(string, integer, integer, string, integer)
s1 = "ABC"
s2 = "DEF"
req = "<methodCall><methodName>Test.concat</methodName><params><param><value><string>" + s1 + "</string></value></param><param><value><string>" + s2 + "</string></value></param></params></methodCall>"
ctx = vms_http_post(host, port, "/", "text/xml", "text/xml", req)
n = vms_http_recv_all(ctx, resp, resplen)
call vms_http_close(ctx)
ixstart = 1
ixend = len(resp)
if grab(mid$(resp, 1, resplen), ixstart, ixend, "value", 1) <> 0 then
if grab(mid$(resp, 1, resplen), ixstart, ixend, "string", 1) <> 0 then
s3 = mid$(resp, ixstart, ixend - ixstart)
print s3
else
s3 = mid$(resp, ixstart, ixend - ixstart)
print s3
end if
end if
end sub
!
function integer grab(string xmlstr, integer xstart, integer xend, string tag, integer greedy)
declare string starttag, endtag
declare integer ixstart, ixend
starttag = "<" + tag + ">"
endtag = "</" + tag + ">"
ixstart = xstart
while (ixstart < (len(xmlstr) - len(starttag))) and (mid$(xmlstr, ixstart, len(starttag))) <> starttag
ixstart = ixstart + 1
next
ixstart = ixstart + len(starttag)
if greedy <> 0 then
ixend = xend - len(endtag)
while (ixend > 1) and (mid$(xmlstr, ixend, len(endtag)) <> endtag)
ixend = ixend - 1
next
else
ixend = ixstart
while (ixend < (len(xmlstr) - len(starttag))) and (mid$(xmlstr, ixend, len(endtag)) <> endtag)
ixend = ixend + 1
next
end if
if (ixstart < len(xmlstr) - len(starttag)) and (ixend >= 1) then
xstart = ixstart
xend = ixend
grab = 1
else
grab = 0
end if
end function
$ bas diyclient
$ link diyclient + xmlrpcdir:xmlrpc/lib
$ run diyclient
Basic is as good as Pascal.
Version | Date | Description |
---|---|---|
1.0 | February 11th 2024 | Initial version |
See list of all articles here
Please send comments to Arne Vajhøj