]> mj.ucw.cz Git - libucw.git/blob - sherlock/xml/xml-test.c
db252c8ddd3b5446f84540e5fa1cb977439bf86d
[libucw.git] / sherlock / xml / xml-test.c
1 /*
2  *      Sherlock Library -- A simple XML parser
3  *
4  *      (c) 2007 Pavel Charvat <pchar@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include "sherlock/sherlock.h"
11 #include "sherlock/xml/xml.h"
12 #include "lib/getopt.h"
13 #include "lib/fastbuf.h"
14
15 #include <stdio.h>
16 #include <stdlib.h>
17
18 enum {
19   WANT_FIRST = 0x100,
20   WANT_PARSE_DTD,
21   WANT_HIDE_ERRORS,
22   WANT_UNFOLD_CDATA,
23   WANT_IGNORE_COMMENTS,
24   WANT_IGNORE_PIS,
25 };
26
27 static char *shortopts = "spd" CF_SHORT_OPTS;
28 static struct option longopts[] = {
29   CF_LONG_OPTS
30   { "sax",              0, 0, 's' },
31   { "pull",             0, 0, 'p' },
32   { "dom",              0, 0, 'd' },
33   { "dtd",              0, 0, WANT_PARSE_DTD },
34   { "hide-errors",      0, 0, WANT_HIDE_ERRORS },
35   { "unfold-cdata",     0, 0, WANT_UNFOLD_CDATA },
36   { "ignore-comments",  0, 0, WANT_IGNORE_COMMENTS },
37   { "ignore-pis",       0, 0, WANT_IGNORE_PIS },
38   { NULL,               0, 0, 0 }
39 };
40
41 static void NONRET
42 usage(void)
43 {
44   fputs("\
45 Usage: xml-test [options] < input.xml\n\
46 \n\
47 Options:\n"
48 CF_USAGE
49 "\
50 -p, --pull              Test PULL interface\n\
51 -s, --sax               Test SAX interface\n\
52 -d, --dom               Test DOM interface\n\
53     --dtd               Enable parsing of DTD\n\
54     --hide-errors       Hide warnings and error messages\n\
55     --unfold-cdata      Unfold CDATA sections\n\
56     --ignore-comments   Ignore processing instructions\n\
57     --ignore-pis        Ignore comments\n\
58 \n", stderr);
59   exit(1);
60 }
61
62 static uns want_sax;
63 static uns want_pull;
64 static uns want_dom;
65 static uns want_parse_dtd;
66 static uns want_hide_errors;
67 static uns want_unfold_cdata;
68 static uns want_ignore_comments;
69 static uns want_ignore_pis;
70
71 static struct fastbuf *out;
72
73 static char *
74 node_type(struct xml_node *node)
75 {
76   switch (node->type)
77     {
78       case XML_NODE_ELEM: return "element";
79       case XML_NODE_COMMENT: return "comment";
80       case XML_NODE_PI: return "pi";
81       case XML_NODE_CHARS: return "chars";
82       default: return "unknown";
83     }
84 }
85
86 static void
87 show_node(struct xml_node *node)
88 {
89   switch (node->type)
90     {
91       case XML_NODE_ELEM:
92         bprintf(out, " <%s>", node->name);
93         XML_ATTR_FOR_EACH(a, node)
94           bprintf(out, " %s='%s'", a->name, a->val);
95         bputc(out, '\n');
96         break;
97       case XML_NODE_COMMENT:
98         bprintf(out, " text='%s'\n", node->text);
99         break;
100       case XML_NODE_PI:
101         bprintf(out, " target=%s text='%s'\n", node->name, node->text);
102         break;
103       case XML_NODE_CHARS:
104         bprintf(out, " text='%s'\n", node->text);
105         break;
106       default:
107         bputc(out, '\n');
108     }
109 }
110
111 static void
112 show_tree(struct xml_node *node, uns level)
113 {
114   if (!node)
115     return;
116   bputs(out, "DOM:  ");
117   for (uns i = 0; i < level; i++)
118     bputs(out, "    ");
119   bputs(out, node_type(node));
120   show_node(node);
121   if (node->type == XML_NODE_ELEM)
122     XML_NODE_FOR_EACH(son, node)
123       show_tree(son, level + 1);
124 }
125
126 static void
127 h_error(struct xml_context *ctx)
128 {
129   bprintf(out, "SAX:  %s at %u: %s\n", (ctx->err_code < XML_ERR_ERROR) ? "warn" : "error", xml_row(ctx), ctx->err_msg);
130 }
131
132 static void
133 h_document_start(struct xml_context *ctx UNUSED)
134 {
135   bputs(out, "SAX:  document_start\n");
136 }
137
138 static void
139 h_document_end(struct xml_context *ctx UNUSED)
140 {
141   bputs(out, "SAX:  document_end\n");
142 }
143
144 static void
145 h_xml_decl(struct xml_context *ctx)
146 {
147   bprintf(out, "SAX:  xml_decl version=%s standalone=%d\n", ctx->version_str, ctx->standalone);
148 }
149
150 static void
151 h_doctype_decl(struct xml_context *ctx)
152 {
153   bprintf(out, "SAX:  doctype_decl type=%s public='%s' system='%s' extsub=%d intsub=%d\n",
154     ctx->doctype, ctx->public_id ? : "", ctx->system_id ? : "",
155     !!(ctx->flags & XML_HAS_EXTERNAL_SUBSET), !!(ctx->flags & XML_HAS_INTERNAL_SUBSET));
156 }
157
158 static void
159 h_comment(struct xml_context *ctx)
160 {
161   bputs(out, "SAX:  comment");
162   show_node(ctx->node);
163 }
164
165 static void
166 h_pi(struct xml_context *ctx)
167 {
168   bputs(out, "SAX:  pi");
169   show_node(ctx->node);
170 }
171
172 static void
173 h_stag(struct xml_context *ctx)
174 {
175   bputs(out, "SAX:  stag");
176   show_node(ctx->node);
177 }
178
179 static void
180 h_etag(struct xml_context *ctx)
181 {
182   bprintf(out, "SAX:  etag </%s>\n", ctx->node->name);
183 }
184
185 static void
186 h_chars(struct xml_context *ctx)
187 {
188   bputs(out, "SAX:  chars");
189   show_node(ctx->node);
190 }
191
192 static void
193 h_cdata(struct xml_context *ctx)
194 {
195   bputs(out, "SAX:  cdata");
196   show_node(ctx->node);
197 }
198
199 static void
200 h_dtd_start(struct xml_context *ctx UNUSED)
201 {
202   bputs(out, "SAX:  dtd_start\n");
203 }
204
205 static void
206 h_dtd_end(struct xml_context *ctx UNUSED)
207 {
208   bputs(out, "SAX:  dtd_end\n");
209 }
210
211 int
212 main(int argc, char **argv)
213 {
214   int opt;
215   cf_def_file = NULL;
216   log_init(argv[0]);
217   while ((opt = cf_getopt(argc, argv, shortopts, longopts, NULL)) >= 0)
218     switch (opt)
219       {
220         case 's':
221           want_sax++;
222           break;
223         case 'p':
224           want_pull++;
225           break;
226         case 'd':
227           want_dom++;
228           break;
229         case WANT_PARSE_DTD:
230           want_parse_dtd++;
231           break;
232         case WANT_HIDE_ERRORS:
233           want_hide_errors++;
234           break;
235         case WANT_UNFOLD_CDATA:
236           want_unfold_cdata++;
237           break;
238         case WANT_IGNORE_COMMENTS:
239           want_ignore_comments++;
240           break;
241         case WANT_IGNORE_PIS:
242           want_ignore_pis++;
243           break;
244         default:
245           usage();
246       }
247   if (optind != argc)
248     usage();
249
250   out = bfdopen_shared(1, 4096);
251   struct xml_context ctx;
252   xml_init(&ctx);
253   if (!want_hide_errors)
254     ctx.h_warn = ctx.h_error = ctx.h_fatal = h_error;
255   if (want_sax)
256     {
257       ctx.h_document_start = h_document_start;
258       ctx.h_document_end = h_document_end;
259       ctx.h_xml_decl = h_xml_decl;
260       ctx.h_doctype_decl = h_doctype_decl;
261       ctx.h_comment = h_comment;
262       ctx.h_pi = h_pi;
263       ctx.h_stag = h_stag;
264       ctx.h_etag = h_etag;
265       ctx.h_chars = h_chars;
266       ctx.h_cdata = h_cdata;
267       ctx.h_dtd_start = h_dtd_start;
268       ctx.h_dtd_end = h_dtd_end;
269     }
270   if (want_dom)
271     ctx.flags |= XML_ALLOC_ALL;
272   if (want_parse_dtd)
273     ctx.flags |= XML_PARSE_DTD;
274   if (want_unfold_cdata)
275     ctx.flags |= XML_UNFOLD_CDATA;
276   if (want_ignore_comments)
277     ctx.flags &= ~(XML_REPORT_COMMENTS | XML_ALLOC_COMMENTS);
278   if (want_ignore_pis)
279     ctx.flags &= ~(XML_REPORT_PIS | XML_ALLOC_PIS);
280   xml_set_source(&ctx, bfdopen_shared(0, 4096));
281   bputs(out, "PULL: start\n");
282   if (want_pull)
283     {
284       ctx.pull = XML_PULL_CHARS | XML_PULL_CDATA | XML_PULL_STAG | XML_PULL_ETAG | XML_PULL_COMMENT | XML_PULL_PI;
285       uns state;
286       while (state = xml_next(&ctx))
287         switch (state)
288           {
289             case XML_STATE_CHARS:
290               bputs(out, "PULL: chars");
291               show_node(ctx.node);
292               break;
293             case XML_STATE_CDATA:
294               bputs(out, "PULL: cdata");
295               show_node(ctx.node);
296               break;
297             case XML_STATE_STAG:
298               bputs(out, "PULL: stag");
299               show_node(ctx.node);
300               break;
301             case XML_STATE_ETAG:
302               bprintf(out, "PULL: etag </%s>\n", ctx.node->name);
303               break;
304             case XML_STATE_COMMENT:
305               bputs(out, "PULL: comment");
306               show_node(ctx.node);
307               break;
308             case XML_STATE_PI:
309               bputs(out, "PULL: pi");
310               show_node(ctx.node);
311               break;
312             default:
313               bputs(out, "PULL: unknown\n");
314               break;
315           }
316     }
317   else
318     xml_parse(&ctx);
319   if (ctx.err_code)
320     bprintf(out, "PULL: fatal error at %u: %s\n", xml_row(&ctx), ctx.err_msg);
321   else
322     {
323       bputs(out, "PULL: eof\n");
324       if (want_dom)
325         show_tree(ctx.dom, 0);
326     }
327
328   xml_cleanup(&ctx);
329   bclose(out);
330   return 0;
331 }