- 浏览: 451083 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (101)
- D 语言 (1)
- acl简介 (7)
- acl开发--快速入门 (1)
- acl开发--编译安装 (4)
- acl开发--数据结构篇 (2)
- acl开发--网络篇 (4)
- acl开发--服务器篇 (9)
- acl开发--进程控制篇 (1)
- acl开发--协程篇 (5)
- acl开发--线程篇 (8)
- acl开发--日志篇 (1)
- acl开发--内存篇 (0)
- acl开发--HTTP协议篇 (5)
- acl开发--SMTP篇 (1)
- acl开发--事件篇 (0)
- acl开发--ICMP篇 (1)
- acl开发--SSL篇 (0)
- acl开发--单元测试篇 (0)
- acl开发--字符串处理篇 (2)
- acl开发--配置文件篇 (1)
- acl开发--杂篇 (1)
- acl开发--C开发篇 (2)
- acl开发--文件/目录篇 (1)
- acl开发--缓存篇 (1)
- acl开发--XML篇 (1)
- 杂谈 (1)
- acl_cpp开发--概述 (1)
- acl_cpp开发--编译安装 (1)
- acl_cpp开发--内存池管理 (1)
- acl_cpp开发--线程编程 (1)
- acl_cpp开发--网络通讯 (2)
- acl_cpp开发--服务器开发 (12)
- acl_cpp开发--数据库编程 (1)
- acl_cpp开发--邮件解析库 (0)
- acl_cpp开发--非阻塞网络编程 (6)
- acl_cpp开发--http应用与web开发 (6)
- acl_cpp开发--redis客户端库 (4)
- acl_cpp开发--handlersocket客户端库 (0)
- acl_cpp开发--xml库 (1)
- acl_cpp开发--json库 (0)
- acl_cpp开发--流式编程 (1)
- acl_cpp开发--序列化 (2)
- acl_cpp开发--杂谈 (0)
- acl_cpp开发--杂项 (1)
- acl--新闻 (12)
- redis实践 (3)
最新评论
-
zsxxsz:
2202877 写道你好,请问一下acl库是否可以移植到arm ...
利用ACL开发并发网络服务器 -
taoshengyijiu20008:
非常不错啊
acl 服务器编程框架设计要点 -
lgqss:
最后的例子用了__thread,依然不能用在动态库中?
再谈线程局部变量 -
foxbryant88:
膜拜中~
我为什么要发明一个轮子? -
zsxxsz:
eryueniaobp 写道关于reset的使用,查看了 g ...
使用 acl 库编写高效的 C++ redis 客户端应用
现在 XML 解析器比较多,其实本没有必要在ACL中添加新的XML解析库,象JAVA、PHP、C#的开发者大都习惯于使用XML数据,因为他们有比较好用的XML解析库,而C/C++的程序员可能使用非XML数据的情形比较多,数据格式也各式各样。当然,如果C/C++程序员使用XML数据也有一些成熟的XML解析库,最丰富的解析库之一如libxml2,比较小型的如tinyxml等,这些库功能都比较丰富,但对流的支持可能有些局限性,象libxml2,接口使用起来还比较复杂,也不太容易掌握。经过再三考虑,决定在ACL中添加XML解析库,希望能满足如下功能:
1、接口丰富而简单(看似是矛盾的,呵呵)
2、很好地支持流的处理(可以支持同步网络流及异步网络流)
3、可以比较容易进行查询、添加、删除、遍历等操作,最好能象JS一样进行操作。
经过几个周末努力,终于算是完成了XML解析库并添加进ACL中。为了很好支持异步流,该XML库采用了有限状态机的方式(效率虽可能不是最好,但也不会差),下面对主要的编程接口进行介绍。
一、API 介绍
1、XML容器对象的创建、XML解析树的生成以及XML容器对象的释放
/** * 创建一个 xml 容器对象 * @return {ACL_XML*} 新创建的 xml 对象 */ ACL_API ACL_XML *acl_xml_alloc(void);
当进行XML解析前,首先必须调用 acl_xml_alloc 创建一个XML容易对象。
/** * 解析 xml 数据, 并持续地自动生成 xml 结点树 * @param xml {ACL_XML*} xml 对象 * @param data {const char*} 以 '\0' 结尾的数据字符串, 可以是完整的 xml 数据; * 也可以是不完整的 xml 数据, 允许循环调用此函数, 将不完整数据持续地输入 */ ACL_API void acl_xml_parse(ACL_XML *xml, const char *data);
将 xml 源数据输入,通过 acl_xml_parser进行解析,因为该函数支持数据状态缓冲(采用有限状态机的好处),所以可以非常容易地支持流数据。
/** * 释放一个 xml 对象, 同时释放该对象里容纳的所有 xml 结点 * @param xml {ACL_XML*} xml 对象 */ ACL_API int acl_xml_free(ACL_XML *xml);
最后需要调用 acl_xml_free 来释放 XML 容易对象。
2、XML数据结点的查询
XML数据结点的查询非常方便,有点类似于JAVASCRIPT中的方式(这也是作者的本意,如果象libxml2那样估计别人用起来就会比较麻烦)。在ACL的XML库里提供了非常丰富的查询方式,如下:
/** * 从 xml 对象中获得所有的与所给标签名相同的 xml 结点的集合 * @param xml {ACL_XML*} xml 对象 * @param tag {const char*} 标签名称 * @return {ACL_ARRAY*} 符合条件的 xml 结点集合, 存于 动态数组中, 若返回 NULL 则 * 表示没有符合条件的 xml 结点 */ ACL_API ACL_ARRAY *acl_xml_getElementsByTagName(ACL_XML *xml, const char *tag);
/** * 从 xml 对象中获得所有给定属性名及属性值的 xml 结点元素集合 * @param xml {ACL_XML*} xml 对象 * @param name {const char*} 属性名 * @param value {const char*} 属性值 * @return {ACL_ARRAY*} 符合条件的 xml 结点集合, 存于 动态数组中, 若返回 NULL 则 * 表示没有符合条件的 xml 结点 */ ACL_API ACL_ARRAY *acl_xml_getElementsByAttr(ACL_XML *xml, const char *name, const char *value);
/** * 从 xml 对象中获得所有的与给定属性名 name 的属性值相同的 xml 结点元素集合 * @param xml {ACL_XML*} xml 对象 * @param value {const char*} 属性名为 name 的属性值 * @return {ACL_ARRAY*} 符合条件的 xml 结点集合, 存于 动态数组中, 若返回 NULL 则 * 表示没有符合条件的 xml 结点 */ ACL_API ACL_ARRAY *acl_xml_getElementsByName(ACL_XML *xml, const char *value);
以上三个函数的返回结果都是一个数组对象(ACL中数组对象库的使用请参考ACL中的 acl_array.h),这些数组元素的类型为ACL_XML_NODE,提取这些数组元素的方式如下:
void test(const char *xml_data) { ACL_XML *xml = acl_xml_create(); ACL_ARRAY *a; ACL_ITER iter; acl_xml_parse(xml, xml_data); a = acl_xml_getElementsByTagName(xml, "user"); if (a) { acl_foreach(iter, a) { ACL_XML_NODE *node = (ACL_XML_NODE*) iter.data; printf("tagname: %s\n", acl_vstring_str(node->ltag)); } /* 释放数组对象 */ acl_xml_free_array(a); } acl_xml_free(xml); }
最后,得注意使用 acl_xml_free_array 来释放数组结果集。
另外,还有一些函数用来获得单个结果,如下:
/** * 从 xml 对象中获得指定 id 值的 xml 结点元素的某个属性对象 * @param xml {ACL_XML*} xml 对象 * @param id {const char*} id 值 * @return {ACL_XML_ATTR*} 某 xml 结点的某个属性对象, 若返回 NULL 则表示 * 没有符合条件的属性 */ ACL_API ACL_XML_ATTR *acl_xml_getAttrById(ACL_XML *xml, const char *id); /** * 从 xml 对象中获得指定 id 值的 xml 结点元素的某个属性值 * @param xml {ACL_XML*} xml 对象 * @param id {const char*} id 值 * @return {const char*} 某 xml 结点的某个属性值, 若返回 NULL 则表示没有符合 * 条件的属性 */ ACL_API const char *acl_xml_getAttrValueById(ACL_XML *xml, const char *id); /** * 从 xml 对象中获得指定 id 值的 xml 结点元素 * @param xml {ACL_XML*} xml 对象 * @param id {const char*} id 值 * @return {ACL_XML_NODE*} xml 结点元素, 若返回 NULL 则表示没有符合 * 条件的 xml 结点 */ ACL_API ACL_XML_NODE *acl_xml_getElementById(ACL_XML *xml, const char *id); /** * 从 xml 结点中获得指定属性名的属性对象 * @param node {ACL_XML_NODE*} xml 结点 * @param name {const char*} 属性名称 * @return {ACL_XML_ATTR*} 属性对象, 为空表示不存在 */ ACL_API ACL_XML_ATTR *acl_xml_getElementAttr(ACL_XML_NODE *node, const char *name); /** * 从 xml 结点中获得指定属性名的属性值 * @param node {ACL_XML_NODE*} xml 结点 * @param name {const char*} 属性名称 * @return {const char*} 属性值, 为空表示不存在 */ ACL_API const char *acl_xml_getElementAttrVal(ACL_XML_NODE *node, const char *name);
这些查询接口也非常类似于JAVASCRIPT的查询方式。因为查询结果具有唯一性,所以仅返回一个结果。
3、XML树结点的遍历
XML树结点的遍历遵循ACL框架库中定义的统一遍历方式,所以遍历XML树也非常容易,示例如下:
ACL_XML *xml; ACL_XML_NODE *node; ACL_ITER iter; /*......*/ /* 假设 XML 解析树已经创建完毕 */ /* 遍历整个XML容器对象的所有数据结点 */ acl_foreach(iter, xml) { node = (ACL_XML_NODE*) iter.data; printf("tagname: %s, text: %s\n", acl_vstring_str(node->ltag), acl_vstring_str(node->text)); } /* 遍历某个XML结点的下一级子结点 */ node = acl_xml_getElementById(xml, "id_test"); if (node) { acl_foreach(iter, node) { ACL_XML_NODE *node2 = (ACL_XML_NODE*) iter.data; printf("tagname: %s, text: %s\n", acl_vstring_str(node->ltag), acl_vstring_str(node->text)); } }
4、其它函数
/** * 从 xml 结点删除某个属性对象, 如果该属性为 id 属性, 则同时会从 xml->id_table 中删除 * @param node {ACL_XML_NODE*} xml 结点 * @param name {const char*} 属性名称 * @return {int} 0 表示删除成功, -1: 表示删除失败(有可能是该属性不存在) */ ACL_API int acl_xml_removeElementAttr(ACL_XML_NODE *node, const char *name); /** * 给 xml 结点添加属性, 如果该属性名已存在, 则用新的属性值替换其属性值, 否则 * 创建并添加新的属性对象 * @param node {ACL_XML_NODE*} xml 结点 * @param name {const char*} 属性名称 * @param value {const char*} 属性值 * @return {ACL_XML_ATTR*} 返回该属性对象(有可能是原来的, 也有可能是新的) */ ACL_API ACL_XML_ATTR *acl_xml_addElementAttr(ACL_XML_NODE *node, const char *name, const char *value); /** * 将 xml 对象转储于指定流中 * @param xml {ACL_XML*} xml 对象 * @param fp {ACL_VSTREAM*} 流对象 */ ACL_API void acl_xml_dump(ACL_XML *xml, ACL_VSTREAM *fp);
当然,还有更多的函数未列出,以上仅可能是用户在使用XML库过程中常用的函数接口。
二、举例
下面举一个完整的例子以结束本文。
#include "lib_acl.h" #define STR acl_vstring_str static void parse_xml(int once) { ACL_XML *xml = acl_xml_alloc(); const char *data = "<?xml version=\"1.0\"?>\r\n" "<?xml-stylesheet type=\"text/xsl\"\r\n" "\thref=\"http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl\"?>\r\n" "\t<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.1.2//EN\"\r\n" "\t\"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd\" [\r\n" " <!ENTITY xmllint \"<command>xmllint</command>\">\r\n" "]>\r\n" "<root name='root' id='root_id_1'>\r\n" " <user name='user1' value='zsx1' id='id1'> user zsx1 </user>\r\n" " <user name='user2' value='zsx2' id='id2'> user zsx2 \r\n" " <age year='1972'>my age</age>\r\n" " </user>\r\n" " <user name='user3' value='zsx3' id='id3'> user zsx3 </user>\r\n" "</root>\r\n" "<root name='root' id='root_id_2'>\r\n" " <user name='user1' value='zsx1' id='id1'> user zsx1 </user>\r\n" " <user name='user2' value='zsx2' id='id2'> user zsx2 \r\n" " <!-- date should be the date of the latest change or the release version -->\r\n" " <age year='1972'>my age</age>\r\n" " </user>\r\n" " <user name='user3' value='zsx3' id='id3'> user zsx3 </user>\r\n" "</root>\r\n" "<root name = 'root2' id = 'root_id_3'>\r\n" " <user name = 'user2_1' value = 'zsx2_1' id = 'id2_1'> user zsx2_1 </user>\r\n" " <user name = 'user2_2' value = 'zsx2_2' id = 'id2_2'> user zsx2_2 </user>\r\n" " <user name = 'user2_3' value = 'zsx2_3' id = 'id2_3'> user zsx2_3 \r\n" " <age year = '1978' month = '12' day = '11'> bao bao </age>\r\n" " </user>\r\n" " <!-- still a bit buggy output, will talk to docbook-xsl upstream to fix this -->\r\n" " <!-- <releaseinfo>This is release 0.5 of the xmllint Manual.</releaseinfo> -->\r\n" " <!-- <edition>0.5</edition> -->\r\n" " <user name = 'user2_2' value = 'zsx2_2' id = 'id2_4'> user zsx2_2 </user>\r\n" "</root>\r\n"; const char *ptr; ACL_ITER iter1; int i, total, left; ACL_ARRAY *a; ACL_XML_NODE *pnode; ptr = data; if (once) { /* 一次性地分析完整 xml 数据 */ acl_xml_parse(xml, ptr); } else { /* 每次仅输入一个字节来分析 xml 数据 */ while (*ptr != 0) { char ch2[2]; ch2[0] = *ptr; ch2[1] = 0; acl_xml_parse(xml, ch2); ptr++; } } if (acl_xml_is_complete(xml, "root")) { printf(">> Yes, the xml complete\n"); } else { printf(">> No, the xml not complete\n"); } total = xml->node_cnt; /* 遍历根结点的一级子结点 */ acl_foreach(iter1, xml->root) { ACL_ITER iter2; ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); /* 遍历一级子结点的二级子结点 */ acl_foreach(iter2, node) { ACL_ITER iter3; ACL_XML_NODE *node2 = (ACL_XML_NODE*) iter2.data; printf("\ttag> %s, text: %s\n", STR(node2->ltag), STR(node2->text)); /* 遍历二级子结点的属性 */ acl_foreach(iter3, node2->attr_list) { ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter3.data; printf("\t\tattr> %s: %s\n", STR(attr->name), STR(attr->value)); } } } printf("----------------------------------------------------\n"); /* 从根结点开始遍历 xml 对象的所有结点 */ acl_foreach(iter1, xml) { ACL_ITER iter2; ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; for (i = 1; i < node->depth; i++) { printf("\t"); } printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); /* 遍历 xml 结点的属性 */ acl_foreach(iter2, node->attr_list) { ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter2.data; for (i = 1; i < node->depth; i++) { printf("\t"); } printf("\tattr> %s: %s\n", STR(attr->name), STR(attr->value)); } } /* 根据标签名获得 xml 结点集合 */ printf("--------- acl_xml_getElementsByTagName ----------\n"); a = acl_xml_getElementsByTagName(xml, "user"); if (a) { /* 遍历结果集 */ acl_foreach(iter1, a) { ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); } /* 释放数组对象 */ acl_xml_free_array(a); } /* 查询属性名为 name, 属性值为 user2_1 的所有 xml 结点的集合 */ printf("--------- acl_xml_getElementsByName ------------\n"); a = acl_xml_getElementsByName(xml, "user2_1"); if (a) { /* 遍历结果集 */ acl_foreach(iter1, a) { ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); } /* 释放数组对象 */ acl_xml_free_array(a); } /* 查询属性名为 id, 属性值为 id2_2 的所有 xml 结点集合 */ printf("----------- acl_xml_getElementById -------------\n"); pnode = acl_xml_getElementById(xml, "id2_2"); if (pnode) { printf("tag> %s, text: %s\n", STR(pnode->ltag), STR(pnode->text)); /* 遍历该 xml 结点的属性 */ acl_foreach(iter1, pnode->attr_list) { ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter1.data; printf("\tattr_name: %s, attr_value: %s\n", STR(attr->name), STR(attr->value)); } pnode = acl_xml_node_next(pnode); printf("----------------- the id2_2's next node is ---------------------\n"); if (pnode) { printf("-------------- walk node -------------------\n"); /* 遍历该 xml 结点的属性 */ acl_foreach(iter1, pnode->attr_list) { ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter1.data; printf("\tattr_name: %s, attr_value: %s\n", STR(attr->name), STR(attr->value)); } } else { printf("-------------- null node -------------------\n"); } } pnode = acl_xml_getElementById(xml, "id2_3"); if (pnode) { int ndel = 0, node_cnt; /* 删除该结点及其子结点 */ printf(">>>before delete %s, total: %d\n", STR(pnode->ltag), xml->node_cnt); ndel = acl_xml_node_delete(pnode); node_cnt = xml->node_cnt; printf(">>>after delete id2_3(%d deleted), total: %d\n", ndel, node_cnt); } acl_foreach(iter1, xml) { ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; printf(">>tag: %s\n", STR(node->ltag)); } pnode = acl_xml_getElementById(xml, "id2_3"); if (pnode) { printf("-------------- walk %s node -------------------\n", STR(pnode->ltag)); /* 遍历该 xml 结点的属性 */ acl_foreach(iter1, pnode->attr_list) { ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter1.data; printf("\tattr_name: %s, attr_value: %s\n", STR(attr->name), STR(attr->value)); } } else { printf("---- the id2_3 be deleted----\n"); } /* 释放 xml 对象 */ left = acl_xml_free(xml); printf("free all node ok, total(%d), left is: %d\n", total, left); } static void parse_xml_file(const char *filepath, int once) { char *data = acl_vstream_loadfile(filepath); ACL_VSTREAM *fp; char *ptr; ACL_XML *xml; struct timeval begin, end; if (data == NULL) return; gettimeofday(&begin, NULL); /* 创建 xml 对象 */ xml = acl_xml_alloc(); ptr = data; if (once) { /* 一次性地分析完整 xml 数据 */ acl_xml_parse(xml, ptr); } else { /* 每次仅输入一个字节来分析 xml 数据 */ while (*ptr) { char ch2[2]; ch2[0] = *ptr; ch2[1] = 0; acl_xml_parse(xml, ch2); ptr++; } } gettimeofday(&end, NULL); printf("------ok, time: %ld seconds, %ld microseconds -------\r\n", end.tv_sec - begin.tv_sec, end.tv_usec - begin.tv_usec); fp = acl_vstream_fopen("dump.txt", O_RDWR | O_CREAT | O_TRUNC, 0600, 4096); /* 将 xml 对象转储至指定流中 */ acl_xml_dump(xml, fp); acl_vstream_fclose(fp); acl_xml_free(xml); acl_myfree(data); } static void usage(const char *procname) { printf("usage: %s -h[help] -f {xml_file} -s[parse once]\n", procname); } int main(int argc, char *argv[]) { int ch, once = 0; char filepath[256]; acl_init(); snprintf(filepath, sizeof(filepath), "xmlcatalog_man.xml"); while ((ch = getopt(argc, argv, "hf:s")) > 0) { switch (ch) { case 'h': usage(argv[0]); return (0); case 'f': snprintf(filepath, sizeof(filepath), "%s", optarg); break; case 's': once = 1; break; default: break; } } parse_xml(once); parse_xml_file(filepath, once); #ifdef ACL_MS_WINDOWS printf("ok, enter any key to exit ...\n"); getchar(); #endif return 0; }
个人微博:http://weibo.com/zsxxsz
相关推荐
ACL的流式解析器允许开发者逐行读取和解析XML或JSON数据,而不必一次性加载整个文件到内存,这对于处理大文件或高流量的网络通信场景尤其有用,能有效降低内存消耗。 6. **HTTP Ping应用协议**:ACL可能还支持...
5. **流式XML/JSON解析器**:XML和JSON是常见的数据交换格式,ACL库内置的解析器能够高效地处理这两种格式的数据,使得在服务器端进行数据解析和生成变得更加便捷。 6. **HTTP应用协议**:ACL库支持HTTP协议,包括...
acl 框架库是一个 C 库,主要包含:服务器开发框架、同步/异步网络通讯、常用数据结构、进程池/线程池、流式 xml/json 解析器、http/ping 应用协议等内容;
Powershell ACL 解析器 解析 Cisco ACL 列表并输出到格式化的 XML 文件。 与我在网上找到的其他格式相比,我为该项目提供的基本 ACL 有点独特。 如果您发现无法正确解析的 ACL 格式,请告诉我,我将使用该格式以符合...
在传统的XML处理中,开发人员需要使用解析器、DOM(文档对象模型)实现、XSL处理器等工具,并决定如何存储XML数据,如文件系统、本地XML数据库或CLOB(大型对象)字段。这种做法不仅复杂,而且往往导致代码量大、...
在传统的 XML 应用中,开发者需要使用解析器、DOM 实现和 XSL 处理器等工具,并且需要编写大量的 DOM 编程代码,这不仅复杂冗长,而且增加了出错的可能性,导致维护成本高昂。 Oracle XML DB 提供了简化的 API,...
acl 框架库是一个 C 库,主要包含:服务器开发框架、同步/异步网络通讯、常用数据结构、进程池/线程池、流式 xml/json 解析器、http/ping 应用协议等内容。 acl 包括以下丰富的常用函数库: 1、常见网络应用库:SMTP...
在传统的XML管理中,你需要一系列工具,如解析器、DOM实现和XSL处理器。DOM编程对于处理XML而言是复杂且冗长的,它需要开发者具备特定的技能,例如DOM编程。这种编程方式不仅成本高昂(据提到每行代码大约花费50美元...
javax.swing.text.html.parser 提供默认的 HTML 解析器以及支持类。 javax.swing.text.rtf 提供一个类 (RTFEditorKit),用于创建富文本格式(Rich-Text-Format)的文本编辑器。 javax.swing.tree 提供处理 javax....
XML处理则由Poco::XML库负责,它实现了完整的DOM(文档对象模型)解析器,允许开发者解析、修改和创建XML文档。Poco::XML::Document对象代表整个XML文档,而Poco::XML::Node接口则表示XML文档中的节点,包括元素、...
javax.swing.text.html.parser 提供默认的 HTML 解析器以及支持类。 javax.swing.text.rtf 提供一个类 (RTFEditorKit),用于创建富文本格式(Rich-Text-Format)的文本编辑器。 javax.swing.tree 提供处理 javax....
javax.swing.text.html.parser 提供默认的 HTML 解析器以及支持类。 javax.swing.text.rtf 提供一个类 (RTFEditorKit),用于创建富文本格式(Rich-Text-Format)的文本编辑器。 javax.swing.tree 提供处理 javax....
javax.swing.text.html.parser 提供默认的 HTML 解析器以及支持类。 javax.swing.text.rtf 提供一个类 (RTFEditorKit),用于创建富文本格式(Rich-Text-Format)的文本编辑器。 javax.swing.tree 提供处理 javax....
javax.swing.text.html.parser 提供默认的 HTML 解析器以及支持类。 javax.swing.text.rtf 提供一个类 (RTFEditorKit),用于创建富文本格式(Rich-Text-Format)的文本编辑器。 javax.swing.tree 提供处理 javax....
在 Java 中,可以使用 JAXB 或 SAX 解析器将 XML 转换为 Java 对象;在 PL/SQL 中,可以使用 XMLType 类型和相关函数处理 XML。 **源码** 在 Java 中,调用 Web Service 的代码可能如下: ```java ...
javax.swing.text.html.parser 提供默认的 HTML 解析器以及支持类。 javax.swing.text.rtf 提供一个类 (RTFEditorKit),用于创建富文本格式(Rich-Text-Format)的文本编辑器。 javax.swing.tree 提供处理 javax....