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.
10 #include "sherlock/sherlock.h"
11 #include "sherlock/xml/xml.h"
12 #include "sherlock/xml/dtd.h"
13 #include "lib/getopt.h"
14 #include "lib/fastbuf.h"
29 static char *shortopts = "spdt" CF_SHORT_OPTS;
30 static struct option longopts[] = {
33 { "pull", 0, 0, 'p' },
36 { "hide-errors", 0, 0, WANT_HIDE_ERRORS },
37 { "ignore-comments", 0, 0, WANT_IGNORE_COMMENTS },
38 { "ignore-pis", 0, 0, WANT_IGNORE_PIS },
39 { "reports-blocks", 0, 0, WANT_REPORT_BLOCKS },
40 { "file-entities", 0, 0, WANT_FILE_ENTITIES },
48 Usage: xml-test [options] < input.xml\n\
53 -p, --pull Test PULL interface\n\
54 -s, --sax Test SAX interface\n\
55 -t, --dom Test DOM interface\n\
56 -d, --dtd Enable parsing of DTD\n\
57 --hide-errors Hide warnings and error messages\n\
58 --ignore-comments Ignore processing instructions\n\
59 --ignore-pis Ignore comments\n\
60 --report-blocks Report blocks or characters and CDATA sections\n\
61 --file-entities Resolve file external entities (not fully normative)\n\
69 static uns want_parse_dtd;
70 static uns want_hide_errors;
71 static uns want_ignore_comments;
72 static uns want_ignore_pis;
73 static uns want_report_blocks;
74 static uns want_file_entities;
76 static struct fastbuf *out;
79 node_type(struct xml_node *node)
83 case XML_NODE_ELEM: return "element";
84 case XML_NODE_COMMENT: return "comment";
85 case XML_NODE_PI: return "pi";
86 case XML_NODE_CHARS: return "chars";
87 default: return "unknown";
92 show_node(struct xml_node *node)
97 bprintf(out, " <%s>", node->name);
98 XML_ATTR_FOR_EACH(a, node)
99 bprintf(out, " %s='%s'", a->name, a->val);
102 case XML_NODE_COMMENT:
103 bprintf(out, " text='%s'\n", node->text);
106 bprintf(out, " target=%s text='%s'\n", node->name, node->text);
109 bprintf(out, " text='%s'\n", node->text);
117 show_tree(struct xml_node *node, uns level)
122 for (uns i = 0; i < level; i++)
124 bputs(out, node_type(node));
126 if (node->type == XML_NODE_ELEM)
127 XML_NODE_FOR_EACH(son, node)
128 show_tree(son, level + 1);
132 h_error(struct xml_context *ctx)
134 bprintf(out, "SAX: %s at %u: %s\n", (ctx->err_code < XML_ERR_ERROR) ? "warn" : "error", xml_row(ctx), ctx->err_msg);
138 h_document_start(struct xml_context *ctx UNUSED)
140 bputs(out, "SAX: document_start\n");
144 h_document_end(struct xml_context *ctx UNUSED)
146 bputs(out, "SAX: document_end\n");
150 h_xml_decl(struct xml_context *ctx)
152 bprintf(out, "SAX: xml_decl version=%s standalone=%d fb_encoding=%s\n", ctx->version_str, ctx->standalone, ctx->src->fb_encoding);
156 h_doctype_decl(struct xml_context *ctx)
158 bprintf(out, "SAX: doctype_decl type=%s public='%s' system='%s' extsub=%d intsub=%d\n",
159 ctx->doctype, ctx->public_id ? : "", ctx->system_id ? : "",
160 !!(ctx->flags & XML_HAS_EXTERNAL_SUBSET), !!(ctx->flags & XML_HAS_INTERNAL_SUBSET));
164 h_comment(struct xml_context *ctx)
166 bputs(out, "SAX: comment");
167 show_node(ctx->node);
171 h_pi(struct xml_context *ctx)
173 bputs(out, "SAX: pi");
174 show_node(ctx->node);
178 h_stag(struct xml_context *ctx)
180 bputs(out, "SAX: stag");
181 show_node(ctx->node);
185 h_etag(struct xml_context *ctx)
187 bprintf(out, "SAX: etag </%s>\n", ctx->node->name);
191 h_chars(struct xml_context *ctx)
193 bputs(out, "SAX: chars");
194 show_node(ctx->node);
198 h_block(struct xml_context *ctx UNUSED, char *text, uns len UNUSED)
200 bprintf(out, "SAX: block text='%s'\n", text);
204 h_cdata(struct xml_context *ctx UNUSED, char *text, uns len UNUSED)
206 bprintf(out, "SAX: cdata text='%s'\n", text);
210 h_dtd_start(struct xml_context *ctx UNUSED)
212 bputs(out, "SAX: dtd_start\n");
216 h_dtd_end(struct xml_context *ctx UNUSED)
218 bputs(out, "SAX: dtd_end\n");
222 h_resolve_entity(struct xml_context *ctx, struct xml_dtd_entity *e)
224 xml_push_fastbuf(ctx, bopen(e->system_id, O_RDONLY, 4096));
228 main(int argc, char **argv)
233 while ((opt = cf_getopt(argc, argv, shortopts, longopts, NULL)) >= 0)
248 case WANT_HIDE_ERRORS:
251 case WANT_IGNORE_COMMENTS:
252 want_ignore_comments++;
254 case WANT_IGNORE_PIS:
257 case WANT_REPORT_BLOCKS:
258 want_report_blocks++;
260 case WANT_FILE_ENTITIES:
261 want_file_entities++;
269 out = bfdopen_shared(1, 4096);
270 struct xml_context ctx;
272 if (!want_hide_errors)
273 ctx.h_warn = ctx.h_error = ctx.h_fatal = h_error;
276 ctx.h_document_start = h_document_start;
277 ctx.h_document_end = h_document_end;
278 ctx.h_xml_decl = h_xml_decl;
279 ctx.h_doctype_decl = h_doctype_decl;
280 ctx.h_comment = h_comment;
284 ctx.h_chars = h_chars;
285 if (want_report_blocks)
287 ctx.h_block = h_block;
288 ctx.h_cdata = h_cdata;
290 ctx.h_dtd_start = h_dtd_start;
291 ctx.h_dtd_end = h_dtd_end;
294 ctx.flags |= XML_ALLOC_ALL;
296 ctx.flags |= XML_PARSE_DTD;
297 if (want_ignore_comments)
298 ctx.flags &= ~(XML_REPORT_COMMENTS | XML_ALLOC_COMMENTS);
300 ctx.flags &= ~(XML_REPORT_PIS | XML_ALLOC_PIS);
301 if (want_file_entities)
302 ctx.h_resolve_entity = h_resolve_entity;
303 xml_push_fastbuf(&ctx, bfdopen_shared(0, 4096));
304 bputs(out, "PULL: start\n");
307 ctx.pull = XML_PULL_CHARS | XML_PULL_STAG | XML_PULL_ETAG | XML_PULL_COMMENT | XML_PULL_PI;
309 while (state = xml_next(&ctx))
312 case XML_STATE_CHARS:
313 bputs(out, "PULL: chars");
317 bputs(out, "PULL: stag");
321 bprintf(out, "PULL: etag </%s>\n", ctx.node->name);
323 case XML_STATE_COMMENT:
324 bputs(out, "PULL: comment");
328 bputs(out, "PULL: pi");
332 bputs(out, "PULL: unknown\n");
339 bprintf(out, "PULL: fatal error at %u: %s\n", xml_row(&ctx), ctx.err_msg);
342 bputs(out, "PULL: eof\n");
344 show_tree(ctx.dom, 0);