标题:Tuxedo 8.1 XML C++ Parser的使用 | 浏览次数: | 时间:2003-12-05 |
---|---|---|
![]() | ||
作者:经乾(dev2dev ID: jq75) BEA系统(中国)有限公司 渠道部技术顾问 |
|
在TUXEDO 8.0中,客户机和服务器之间可以使用XML缓冲区进行数据交换,但由于8.0版本没有集成XML Parser,所以对XML的支持是有限的。从8.1版本开始,TUXEDO集成了Apache Xerces C++ Parser 1.7,这样服务器端就可以直接分析XML文档了,而不用再去调用其它XML Parser。
TUXEDO 8.1的samples中给了一个xmlstockapp例子,由于它太复杂(至少我这么认为),因此,本文将通过一个简单实用的例子来介绍XML缓冲区使用。
一.XML缓冲区的分配和传输
XML缓冲区支持的最大长度是4GB,分配方法与CARRAY缓冲区一样,需要指定长度。客户端需要打开一个XML文档,以字符方式读取文档内容,保存到缓冲区中,然后由tpcall()调用提交给服务进程。清单1-1是通信录应用程序的XML客户机代码段。
清单1-1 XML缓冲区客户机代码段,文件名:XML_cli.c
#define XMLDOCSIZE 1048576
... ...
FILE *xml_fd;
char *xml_buffer = NULL;
if ((xml_fd = fopen("friends.xml", "r")) != NULL) {
xml_buffer = (char )malloc(sizeof(char) * XMLDOCSIZE);
nsize = fread(xml_buffer, sizeof(char), XMLDOCSIZE, xml_fd);
}
sendlen = nsize + 1; / 实际读取的长度 */
if((sendbuf = (char *) tpalloc((char *)"XML", NULL, sendlen)) == NULL) {
fprintf(stderr,"Error allocating send buffer, tperrno=%ld\n",tperrno);
tpterm();
return(1);
}
strncpy(sendbuf, xml_buffer, nsize);
ret = tpcall((char *)"ADD_FRIEND", (char *)sendbuf, sendlen, (char **)&rcvbuf, &rcvlen, TPNOTIME);
... ...
复制到缓冲区的XML文件必须遵循1.0标准,可以包含任何自定义的标记。本例中用到了friends.xml,这个文件包含了两条要添加到数据库好友信息,内容如清单1-2所示。
清单1-2 XML文件示例,文件名:friends.xml
1<friends>
2<friend>
3<friend_id>1</friend_id>
4<fname>JQ</fname>
5<fmobile>13910793488</fmobile>
6</friend>
7<friend>
8<friend_id>2</friend_id>
9<fname>Snna</fname>
10<fmobile>13663129935</fmobile>
11</friend>
12</friends>
二.基于XML标记的DDR
XML缓冲区支持基于标记值的DDR,对于通信录应用程序来说,如果我们要把friend_id取值在1-10范围内的记录保存在table1中,把取值在11-20范围内的记录保存在table2中,把其它取值范围的记录保存在table3中,则可以在ubb配置文件中定义下面的路由标准来实现:
ROUTING
symbol FIELD="friends/friend/ friend_id"
BUFTYPE="XML"
FIELDTYPE=LONG
RANGES="1-10:GROUP1,11-20:GROUP2,:GROUP3"
XML缓冲区的路由字段还可以是STRING类型的,这时RANGES的取值必须用单引号引起来,请看如下代码段:
*ROUTING
symbol FIELD="stockquotes/stock_quote/symbol"
BUFTYPE="XML"
FIELDTYPE=STRING
RANGES="'BEAS'-'BEAS':GROUP1, 'MSFT'-'MSFT':GROUP2"
三.XML缓冲区的分析
服务器端收到XML缓冲区后,需要对它进行分析,从中取出标记值。Tuxedo 8.1集成了Apache Xerces C++ Parser 1.7,并提供了两种类型的分析器:SAX Parser和DOM Parser,服务器端通常使用DOM Parser,客户端通常使用SAX Parser。使用Xerces C++ Parser的步骤一般是:
· 初始化XMLC42系统;
XMLPlatformUtils::Initialize();
· 根据XML缓冲区创建MemBufferInputSource;
MemBufInputSource* memBufIS =
new MemBufInputSource( (const XMLByte*)xmlbuf, strlen(xmlbuf), bufId, false);
· 创建SAX Parser或DOM Parser;
DOMParser *parser = new DOMParser;
SAXPArser *parser = new SAXParser;
· 对于SAX Parser,需要为文档和错误处理设置回调函数;
SAXPrintHandlers handler;
parser->setDocumentHandler(&handler);
parser->setErrorHandler(&handler);
· 调用Xerces C++ Parser分析XML缓冲区;
parse->parse(*memBufIS);
· 删除Parser和MemBufferInputSource;
delete parser;
delete memBufIS;
· 退出XMLC42系统;
XMLPlatformUtils::Terminate();
对于通信录应用程序来说,客户机给服务器传递了friends.xml文件,服务器端创建了一个DOM Parser对它进行分析,并把结果存入数据库,代码如清单1-3所示。
清单1-3 XML缓冲区的服务器代码,文件名:XML_serv.pc
#include
1<xercesc domparser.hpp="" parsers="">
2#include <xercesc platformutils.hpp="" util="">
3#include <xercesc framework="" membufinputsource.hpp="">
4#include <atmi.h>
5#include <userlog.h>
6#include <stdlib.h>
7#include <string.h>
8
9char *localbuf=NULL;
10static const char* bufId = "mybuf";
11
12EXEC SQL begin declare section;
13static long friend_id;
14static char fname[10];
15static char fmobile[14];
16EXEC SQL end declare section;
17
18EXEC SQL INCLUDE sqlca;
19
20void TopTree( DOM_Node node);
21void SubTree( DOM_Node node);
22void parseXMLBuffer(char** xmlbuf);
23
24
25#ifdef __cplusplus
26extern "C"
27#endif
28void
29#if defined(__STDC__) || defined(__cplusplus)
30ADD_FRIEND(TPSVCINFO *rqst)
31#else
32ADD_FRIEND(rqst)
33TPSVCINFO *rqst;
34#endif
35{
36parseXMLBuffer(&rqstàdata);
37tpreturn(TPSUCCESS, 0, xmlbuf, rqstàlen, 0);
38}
39void parseXMLBuffer(char** xmlbuf)
40{
41int errorCount ;
42localbuf = (char *)malloc(sizeof(char *) * 2048);
43XMLPlatformUtils::Initialize();
44
45MemBufInputSource* memBufIS =
46new MemBufInputSource( (const XMLByte*)*xmlbuf, strlen(*xmlbuf)-1, bufId, true);
47
48DOMParser *parser = new DOMParser;
49parseràparse(*memBufIS);
50if ((errorCount = parseràgetErrorCount()) == 0)
51{
52DOM_Document document = parseràgetDocument();
53DOM_Element topLevel = document.getDocumentElement();
54TopTree(topLevel);
55}
56delete parser;
57delete memBufIS;
58XMLPlatformUtils::Terminate();
59}
60void TopTree( DOM_Node node){
61if (node.getNodeType() == DOM_Node::ELEMENT_NODE)
62{
63if (node.getNodeName().equals ("friend")) SubTree(node);
64else
65{
66DOM_NodeList children = node.getChildNodes();
67for (int i=0; i<children.getLength(); i++) TopTree(children.item(i));
68}
69}
70}
71void SubTree( DOM_Node node)\
72{
73DOM_NodeList children = node.getChildNodes();
74for (int i=0; i<children.getLength(); i++)
75{
76DOM_Node nod = children.item(i);
77if(nod.getNodeType()==DOM_Node::ELEMENT_NODE)
78{
79if(nod.getNodeName().equals("friend_id"))
80friend_id = atol(nod.getFirstChild().getNodeValue().transcode());
81else if(nod.getNodeName().equals("fname"))
82strcpy(fname, nod.getFirstChild().getNodeValue().transcode());
83else if(nod.getNodeName().equals("fmobile"))
84strcpy(fmobile, nod.getFirstChild().getNodeValue().transcode());
85}
86}
87EXEC SQL insert into FRIEND (FRIEND_ID,NAME,MOBILE)
88values (:friend_id, :fname, :fmobile);
89
90if (SQLCODE != SQL_OK) userlog("Cannot insert into FRIEND");
91}
92
93注意:服务器文件名为XML_serv.pc,先要使用esqlc命令对它作预编译,生成C源程序,然后把扩展名改为cpp,才能用buildserver来编译,原因是Xerces C++ Parser只提供了C++的编程接口。读者可以参考如下命令来编译:
94proc iname=XML_serv.pc oname=XML_serv.cpp
95buildserver -v -s ADD_FRIEND -f XML_serv.cpp -o XML_serv -f %TUXDIR%\lib\libtxml.lib
96
97**四.UBBConfigNT配置文件的编写**
98这个例子使用了Oracle8i数据库来测试,Tuxedo的配置文件如清单1-4所示。
99
100清单1-4 Tuxedo的配置文件,文件名:UBBConfigNT
101*RESOURCES
102IPCKEY 123456
103DOMAINID simpapp
104MASTER SITE1
105MAXACCESSERS 10
106MAXSERVERS 5
107MAXSERVICES 10
108MODEL SHM
109LDBAL N
110
111*MACHINES
112DEFAULT:
113APPDIR="C:\TuxDAP\solutions\xml"
114TUXCONFIG="C:\TuxDAP\solutions\xml\tuxconfig"
115TUXDIR="G:\bea\tuxedo"
116TLOGNAME=TLOG
117TLOGDEVICE="C:\TuxDAP\solutions\xml\TLOG"
118
119JQ LMID=SITE1
120
121*GROUPS
122DEFAULT: LMID=SITE1
123
124GROUP1 LMID=simple GRPNO=1
125OPENINFO="Oracle_XA:Oracle_XA+Acc=P/scott/tiger+SqlNet=oradb+SesTm=120+
126MaxCur=5+LogDir=."
127TMSNAME="TMS_ORA8i" TMSCOUNT=2
128
129*SERVERS
130DEFAULT: RESTART=Y MAXGEN=5 REPLYQ=Y CLOPT="-A"
131XML_serv SRVGRP=GROUP1 SRVID=10
132
133*SERVICES
134ADD_FRIEND
135
136*ROUTING
137
138**五.运行测试**
139执行XML_Cli.exe进行测试,friends.xml文件已经通过XML缓冲区成功地发送到服务器端;
140打开SQL*PLUS,查看一下FRIEND表的内容,发现里面已经插入了两条记录,这两条记录的数据就是通过friends.xml文件来传输的!
141
142
143
144---</string.h></stdlib.h></userlog.h></atmi.h></xercesc></xercesc></xercesc>