c语言使用ekhtml库解析html
El-Kabong 是一个快速的,不带验证的,SAX接口的HTML解析器。 它的目标是提供一个快速,轻量级的解析HTML的库,对于语法不正确的标签也可以识别。
可从sourceforge下载源码:http://sourceforge.net/projects/ekhtml/
* 最新版本ekhtml-0.3.2.
可从sourceforge下载源码:http://sourceforge.net/projects/ekhtml/
* 最新版本ekhtml-0.3.2.
下载完毕后,解压开,进入到解压开的目录下,输入./configure && make编译文档。这些都在INSTALL文件里,可以参考一下。
然后,在src目录下的.lib目录下会有一个libekhtml.a的文件,这个文件就是ekhtml的静态链接库。静态链接库可以看成是.o文件的集合。
最后输入sudo make install就可以将ekhtml库安装到计算机上,ekhtml.h头文件在/usr/local/include目录下,静态链接库和动态链接库在/usr/local/lib目录下。
使用时,包含头文件ekhtml.h就可以了,在链接时要记得加上,/usr/local/lib/libekhtml.a文件。
下面是链接库的官方文档:
Libraries have been installed in:
/usr/local/lib
If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,--rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to `/etc/ld.so.conf'
See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
/usr/local/lib
If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,--rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to `/etc/ld.so.conf'
See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
这个是官方给的测试程序:
编译命令为:gcc -o tester tester.c /usr/local/lib/libekhtml.a
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158/* * Copyright (c) 2002, Jon Travis * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include "ekhtml.h" #define MAGIC_DOODIE 0xf9d33bc1 typedef struct { unsigned int n_starttags; unsigned int n_endtags; unsigned int n_comments; unsigned int n_data; unsigned int magic_doodie; unsigned int only_parse; } tester_cbdata; static void handle_starttag_way(void *cbdata, ekhtml_string_t *tag, ekhtml_attr_t *attrs) { printf("GOT WAY START!n"); } static void handle_starttag(void *cbdata, ekhtml_string_t *tag, ekhtml_attr_t *attrs) { ekhtml_attr_t *attr; tester_cbdata *tdata = cbdata; assert(tdata->magic_doodie == MAGIC_DOODIE); tdata->n_starttags++; if(tdata->only_parse) return; printf("START: "%.*s"n", (int)tag->len, tag->str); for(attr=attrs; attr; attr=attr->next) { printf("ATTRIBUTE: "%.*s" = ", (int)attr->name.len, attr->name.str); if(!attr->isBoolean) printf(""%.*s"n", (int)attr->val.len, attr->val.str); else printf(""%.*s"n", (int)attr->name.len, attr->name.str); } } static void handle_endtag(void *cbdata, ekhtml_string_t *str){ tester_cbdata *tdata = cbdata; assert(tdata->magic_doodie == MAGIC_DOODIE); tdata->n_endtags++; if(tdata->only_parse) return; printf("END: "%.*s"n", (int)str->len, str->str); } static void handle_comment(void *cbdata, ekhtml_string_t *str){ tester_cbdata *tdata = cbdata; assert(tdata->magic_doodie == MAGIC_DOODIE); tdata->n_comments++; if(tdata->only_parse) return; printf("COMMENT: "%.*s"n", (int)str->len, str->str); } static void handle_data(void *cbdata, ekhtml_string_t *str){ tester_cbdata *tdata = cbdata; assert(tdata->magic_doodie == MAGIC_DOODIE); tdata->n_data++; if(tdata->only_parse) return; fwrite(str->str, str->len, 1, stdout); } int main(int argc, char *argv[]){ tester_cbdata cbdata; ekhtml_parser_t *ekparser; char *buf; size_t nbuf; int feedsize; if(argc < 2){ fprintf(stderr, "Syntax: %s <feedsize> [1|0 (to print debug)]n", argv[0]); return -1; } feedsize = atoi(argv[1]); ekparser = ekhtml_parser_new(NULL); cbdata.n_starttags = 0; cbdata.n_endtags = 0; cbdata.n_comments = 0; cbdata.n_data = 0; cbdata.magic_doodie = MAGIC_DOODIE; cbdata.only_parse = argc == 3; ekhtml_parser_datacb_set(ekparser, handle_data); ekhtml_parser_commentcb_set(ekparser, handle_comment); ekhtml_parser_startcb_add(ekparser, "WAY", handle_starttag_way); ekhtml_parser_startcb_add(ekparser, NULL, handle_starttag); ekhtml_parser_endcb_add(ekparser, NULL, handle_endtag); ekhtml_parser_cbdata_set(ekparser, &cbdata); buf = malloc(feedsize); while((nbuf = fread(buf, 1, feedsize, stdin))){ ekhtml_string_t str; str.str = buf; str.len = nbuf; ekhtml_parser_feed(ekparser, &str); ekhtml_parser_flush(ekparser, 0); } ekhtml_parser_flush(ekparser, 1); ekhtml_parser_destroy(ekparser); free(buf); if(argc == 3){ fprintf(stderr, "# starttags: %un" "# endtags: %un" "# comments: %un" "# data: %un", cbdata.n_starttags, cbdata.n_endtags, cbdata.n_comments, cbdata.n_data); } return 0; }
可见,使用ekhtml库的时候,是很方便的,只需要包含进来ekhtml.h头文件就可以使用它的函数了。
下面来介绍一下ekhtml函数的使用(官方的文档在docs文件夹下):
ekhtml中有两个结构体,一个是ekhtml_attr_t,用来表示标签的属性,定义如下:
复制代码
这个结构体将会传递给回调函数,属性的名字和属性的值都是ekhtml_string_t类型,是另一个结构体,官方说是因为速度的原因没有使用''结尾的字符串。
1
2
3
4
5
6
7typedef struct ekhtml_attr_t { ekhtml_string_t name; /**< Name of the attribute */ ekhtml_string_t val; /**< Value of the attribute */ unsigned int isBoolean; /**< True of the attribute is boolean */ struct ekhtml_attr_t *next; /**< Pointer to next attribute in the list */ } ekhtml_attr_t;
ekhtml_string_t的定义如下:
复制代码
ekhtml_string_t表示一个字符串,不过这个字符串用len字段表明这个字符串的长度。
1
2
3
4
5typedef struct ekhtml_string_t { const char *str; /**< Actual string data */ size_t len; /**< Length of the data in `str` */ } ekhtml_string_t;
常用函数:
1,ekhtml_parser_t *ekhtml_parser_new(void *cbdata)
创建一个解析html的对象,返回其指针,参数时要传递给回调函数的参数。
ekhtml_parser_t是一个html的解析对象,有兴趣可以参见源代码中它的定义。
可以先不设置,然后使用ekhtml_parser_cbdata_set函数来设置。
2,void ekhtml_parser_datacb_set(ekhtml_parser_t *parser, ekhtml_data_cb_t cb)
这个用来设置标签内的内容处理的回调函数,标签内容和设置的回调函数参数会传递给回调函数。
ekhtml_data_cb_t是一个函数的指针类型,定义为:
复制代码
cbdata为自己设置的回调函数参数,ekhtml_string_t为标签内容。
1typedef void (*ekhtml_data_cb_t)(void *cbdata, ekhtml_string_t *data);
3,void ekhtml_parser_commentcb_set(ekhtml_parser_t *parser, ekhtml_data_cb_t cb)
这个用来设置html注释的内容处理的回调函数,注释内容和设置的回调函数参数会传递给回调函数。
回调函数类型与2一样。
4,void ekhtml_parser_startcb_add(ekhtml_parser_t *parser, const char *tag, ekhtml_starttag_cb_t cb)
这个函数用来设置当一个标签开始时的回调函数,tag参数为标签的名字(不区分大小写),第三个参数为回调函数。
当为tag参数为NULL时,对任意规范和非规范标签都调用回调函数,如果对某一个特定标签名指定了另外的回调函数,那么就会只
执行这个回调函数。也就是说,可以为不同的标签添加不同的回调函数。
ekhtml_starttag_cb_t的定义如下:
复制代码
回调函数的第一个参数为自己设置的参数,第二个为标签名字,第三个为属性链表。
1typedef void (*ekhtml_starttag_cb_t)(void *cbdata, ekhtml_string_t *tag, ekhtml_attr_t *attrs);
5,void ekhtml_parser_endcb_add(ekhtml_parser_t *parser, const char *tag, ekhtml_endtag_cb_t cb)
这个函数用来设置当一个标签结束时的回调函数,tag参数为标签的名字(不区分大小写),第三个参数为回调函数。
当为tag参数为NULL时,对任意规范和非规范标签都调用回调函数,如果对某一个特定标签名指定了另外的回调函数,那么就会只
执行这个回调函数。也就是说,可以为不同的标签添加不同的回调函数。
ekhtml_endtag_cb_t的定义如下:
复制代码
回调函数的第一个参数为自己设置的参数,第二个为标签名字。
1typedef void (*ekhtml_endtag_cb_t)(void *cbdata, ekhtml_string_t *tag);
6,void ekhtml_parser_cbdata_set(ekhtml_parser_t *parser, void *cbdata)
这个函数用来设置回调函数的自定义参数,cbdata为参数的指针,可以为结构体。
7,void ekhtml_parser_destroy(ekhtml_parser_t *parser)
这个函数销毁一个使用ekhtml_parser_new创建的解析html对象。这两个函数应该成对出现,否则会导致内存泄露。
8,void ekhtml_parser_feed(ekhtml_parser_t *parser, ekhtml_string_t *data)
将需要处理的html数据传递给解析器,data为html字符串。这个函数将数据存放在内部缓冲区中,直到内部缓冲区满了,就刷新
数据,并且重新填入。如果传入的数据比内部缓冲区大,就重新分配内部缓冲区的大小。
9,int ekhtml_parser_flush(ekhtml_parser_t *parser, int flushall)
这个函数刷新解析器的内部缓冲区,已经处理过的数据会从缓冲区中移除,并且内部缓冲区会重新组织。第二个参数如果为真,则强制刷新全部,即使标签没有结束,如<h2。
函数如果执行了动作,返回1,否则,返回0。
ekhtml库中的函数就只有这9个了。可以通过自己传入的参数记录状态,来获取特定的数据。
我把ekhtml的源代码放到了我的github上,方便下载:https://github.com/gwq5210/ekhtml.git
参考:
1)http://blog.csdn.net/jq0123/article/details/1328786
最后
以上就是繁荣便当最近收集整理的关于c语言使用ekhtml库解析html的全部内容,更多相关c语言使用ekhtml库解析html内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复