2 * Sherlock Library -- A simple XML parser
4 * (c) 2007--2008 Pavel Charvat <pchar@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
13 #include <ucw/getopt.h>
14 #include <ucw/fastbuf.h>
26 WANT_REPORT_IGNORABLE,
30 static char *shortopts = "spdt" CF_SHORT_OPTS;
31 static struct option longopts[] = {
34 { "pull", 0, 0, 'p' },
37 { "hide-errors", 0, 0, WANT_HIDE_ERRORS },
38 { "ignore-comments", 0, 0, WANT_IGNORE_COMMENTS },
39 { "ignore-pis", 0, 0, WANT_IGNORE_PIS },
40 { "report-blocks", 0, 0, WANT_REPORT_BLOCKS },
41 { "report-ignorable", 0, 0, WANT_REPORT_IGNORABLE },
42 { "file-entities", 0, 0, WANT_FILE_ENTITIES },
50 Usage: xml-test [options] < input.xml\n\
55 -p, --pull Test PULL interface\n\
56 -s, --sax Test SAX interface\n\
57 -t, --dom Test DOM interface\n\
58 -d, --dtd Enable parsing of DTD\n\
59 --hide-errors Hide warnings and error messages\n\
60 --ignore-comments Ignore comments\n\
61 --ignore-pis Ignore processing instructions\n\
62 --report-blocks Report blocks or characters and CDATA sections\n\
63 --report-ignorable Report ignorable whitespace\n\
64 --file-entities Resolve file external entities (not fully normative)\n\
70 static uint want_pull;
72 static uint want_parse_dtd;
73 static uint want_hide_errors;
74 static uint want_ignore_comments;
75 static uint want_ignore_pis;
76 static uint want_report_blocks;
77 static uint want_report_ignorable;
78 static uint want_file_entities;
80 static struct fastbuf *out;
83 node_type(struct xml_node *node)
87 case XML_NODE_ELEM: return "element";
88 case XML_NODE_COMMENT: return "comment";
89 case XML_NODE_PI: return "pi";
90 case XML_NODE_CHARS: return "chars";
91 default: return "unknown";
96 show_node(struct xml_node *node)
101 bprintf(out, " <%s>", node->name);
102 XML_ATTR_FOR_EACH(a, node)
103 bprintf(out, " %s='%s'", a->name, a->val);
106 case XML_NODE_COMMENT:
107 bprintf(out, " text='%s'\n", node->text);
110 bprintf(out, " target=%s text='%s'\n", node->name, node->text);
113 bprintf(out, " text='%s'\n", node->text);
121 show_tree(struct xml_node *node, uint level)
126 for (uint i = 0; i < level; i++)
128 bputs(out, node_type(node));
130 if (node->type == XML_NODE_ELEM)
131 XML_NODE_FOR_EACH(son, node)
132 show_tree(son, level + 1);
136 h_error(struct xml_context *ctx)
138 bprintf(out, "SAX: %s at %u: %s\n", (ctx->err_code < XML_ERR_ERROR) ? "warn" : "error", xml_row(ctx), ctx->err_msg);
142 h_document_start(struct xml_context *ctx UNUSED)
144 bputs(out, "SAX: document_start\n");
148 h_document_end(struct xml_context *ctx UNUSED)
150 bputs(out, "SAX: document_end\n");
154 h_xml_decl(struct xml_context *ctx)
156 bprintf(out, "SAX: xml_decl version=%s standalone=%d fb_encoding=%s\n", ctx->version_str, ctx->standalone, ctx->src->fb_encoding);
160 h_doctype_decl(struct xml_context *ctx)
162 bprintf(out, "SAX: doctype_decl type=%s public='%s' system='%s' extsub=%d intsub=%d\n",
163 ctx->doctype, ctx->public_id ? : "", ctx->system_id ? : "",
164 !!(ctx->flags & XML_HAS_EXTERNAL_SUBSET), !!(ctx->flags & XML_HAS_INTERNAL_SUBSET));
168 h_comment(struct xml_context *ctx)
170 bputs(out, "SAX: comment");
171 show_node(ctx->node);
175 h_pi(struct xml_context *ctx)
177 bputs(out, "SAX: pi");
178 show_node(ctx->node);
182 h_stag(struct xml_context *ctx)
184 bputs(out, "SAX: stag");
185 show_node(ctx->node);
189 h_etag(struct xml_context *ctx)
191 bprintf(out, "SAX: etag </%s>\n", ctx->node->name);
195 h_chars(struct xml_context *ctx)
197 bputs(out, "SAX: chars");
198 show_node(ctx->node);
202 h_block(struct xml_context *ctx UNUSED, char *text, uint len UNUSED)
204 bprintf(out, "SAX: block text='%s'\n", text);
208 h_cdata(struct xml_context *ctx UNUSED, char *text, uint len UNUSED)
210 bprintf(out, "SAX: cdata text='%s'\n", text);
214 h_ignorable(struct xml_context *ctx UNUSED, char *text, uint len UNUSED)
216 bprintf(out, "SAX: ignorable text='%s'\n", text);
220 h_dtd_start(struct xml_context *ctx UNUSED)
222 bputs(out, "SAX: dtd_start\n");
226 h_dtd_end(struct xml_context *ctx UNUSED)
228 bputs(out, "SAX: dtd_end\n");
232 h_resolve_entity(struct xml_context *ctx, struct xml_dtd_entity *e)
234 xml_push_fastbuf(ctx, bopen(e->system_id, O_RDONLY, 4096));
238 main(int argc, char **argv)
243 while ((opt = cf_getopt(argc, argv, shortopts, longopts, NULL)) >= 0)
258 case WANT_HIDE_ERRORS:
261 case WANT_IGNORE_COMMENTS:
262 want_ignore_comments++;
264 case WANT_IGNORE_PIS:
267 case WANT_REPORT_BLOCKS:
268 want_report_blocks++;
270 case WANT_REPORT_IGNORABLE:
271 want_report_ignorable++;
273 case WANT_FILE_ENTITIES:
274 want_file_entities++;
282 out = bfdopen_shared(1, 4096);
283 struct xml_context ctx;
285 if (!want_hide_errors)
286 ctx.h_warn = ctx.h_error = ctx.h_fatal = h_error;
289 ctx.h_document_start = h_document_start;
290 ctx.h_document_end = h_document_end;
291 ctx.h_xml_decl = h_xml_decl;
292 ctx.h_doctype_decl = h_doctype_decl;
293 ctx.h_comment = h_comment;
297 ctx.h_chars = h_chars;
298 if (want_report_blocks)
300 ctx.h_block = h_block;
301 ctx.h_cdata = h_cdata;
303 if (want_report_ignorable)
304 ctx.h_ignorable = h_ignorable;
305 ctx.h_dtd_start = h_dtd_start;
306 ctx.h_dtd_end = h_dtd_end;
309 ctx.flags |= XML_ALLOC_ALL;
311 ctx.flags |= XML_PARSE_DTD;
312 if (want_ignore_comments)
313 ctx.flags &= ~(XML_REPORT_COMMENTS | XML_ALLOC_COMMENTS);
315 ctx.flags &= ~(XML_REPORT_PIS | XML_ALLOC_PIS);
316 if (want_file_entities)
317 ctx.h_resolve_entity = h_resolve_entity;
318 xml_push_fastbuf(&ctx, bfdopen_shared(0, 4096));
319 bputs(out, "PULL: start\n");
322 ctx.pull = XML_PULL_CHARS | XML_PULL_STAG | XML_PULL_ETAG | XML_PULL_COMMENT | XML_PULL_PI;
324 while (state = xml_next(&ctx))
327 case XML_STATE_CHARS:
328 bputs(out, "PULL: chars");
332 bputs(out, "PULL: stag");
336 bprintf(out, "PULL: etag </%s>\n", ctx.node->name);
338 case XML_STATE_COMMENT:
339 bputs(out, "PULL: comment");
343 bputs(out, "PULL: pi");
347 bputs(out, "PULL: unknown\n");
354 bprintf(out, "PULL: fatal error at %u: %s\n", xml_row(&ctx), ctx.err_msg);
357 bputs(out, "PULL: eof\n");
359 show_tree(ctx.dom, 0);