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