blob: e854748ee8f69f03042882b5aa7aef686a05e32d [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * SAX.c : Default SAX handler to build a tree.
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * Daniel Veillard <daniel@veillard.com>
Owen Taylor3473f882001-02-23 17:55:21 +00007 */
8
9
Bjorn Reese70a9da52001-04-21 16:57:29 +000010#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000011#include <stdlib.h>
12#include <string.h>
13#include <libxml/xmlmemory.h>
14#include <libxml/tree.h>
15#include <libxml/parser.h>
16#include <libxml/parserInternals.h>
17#include <libxml/valid.h>
18#include <libxml/entities.h>
19#include <libxml/xmlerror.h>
20#include <libxml/debugXML.h>
21#include <libxml/xmlIO.h>
22#include <libxml/SAX.h>
23#include <libxml/uri.h>
Daniel Veillard48da9102001-08-07 01:10:10 +000024#include <libxml/valid.h>
Owen Taylor3473f882001-02-23 17:55:21 +000025#include <libxml/HTMLtree.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000026#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000027
28/* #define DEBUG_SAX */
29/* #define DEBUG_SAX_TREE */
30
31/**
32 * getPublicId:
33 * @ctx: the user data (XML parser context)
34 *
35 * Return the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
36 *
37 * Returns a xmlChar *
38 */
39const xmlChar *
Daniel Veillardc86a4fa2001-03-26 16:28:29 +000040getPublicId(void *ctx ATTRIBUTE_UNUSED)
Owen Taylor3473f882001-02-23 17:55:21 +000041{
42 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
43 return(NULL);
44}
45
46/**
47 * getSystemId:
48 * @ctx: the user data (XML parser context)
49 *
50 * Return the system ID, basically URL or filename e.g.
51 * http://www.sgmlsource.com/dtds/memo.dtd
52 *
53 * Returns a xmlChar *
54 */
55const xmlChar *
56getSystemId(void *ctx)
57{
58 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard56a4cb82001-03-24 17:00:36 +000059 return((const xmlChar *) ctxt->input->filename);
Owen Taylor3473f882001-02-23 17:55:21 +000060}
61
62/**
63 * getLineNumber:
64 * @ctx: the user data (XML parser context)
65 *
66 * Return the line number of the current parsing point.
67 *
68 * Returns an int
69 */
70int
71getLineNumber(void *ctx)
72{
73 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
74 return(ctxt->input->line);
75}
76
77/**
78 * getColumnNumber:
79 * @ctx: the user data (XML parser context)
80 *
81 * Return the column number of the current parsing point.
82 *
83 * Returns an int
84 */
85int
86getColumnNumber(void *ctx)
87{
88 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
89 return(ctxt->input->col);
90}
91
Owen Taylor3473f882001-02-23 17:55:21 +000092/**
93 * isStandalone:
94 * @ctx: the user data (XML parser context)
95 *
96 * Is this document tagged standalone ?
97 *
98 * Returns 1 if true
99 */
100int
101isStandalone(void *ctx)
102{
103 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
104 return(ctxt->myDoc->standalone == 1);
105}
106
107/**
108 * hasInternalSubset:
109 * @ctx: the user data (XML parser context)
110 *
111 * Does this document has an internal subset
112 *
113 * Returns 1 if true
114 */
115int
116hasInternalSubset(void *ctx)
117{
118 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
119 return(ctxt->myDoc->intSubset != NULL);
120}
121
122/**
123 * hasExternalSubset:
124 * @ctx: the user data (XML parser context)
125 *
126 * Does this document has an external subset
127 *
128 * Returns 1 if true
129 */
130int
131hasExternalSubset(void *ctx)
132{
133 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
134 return(ctxt->myDoc->extSubset != NULL);
135}
136
137/**
138 * internalSubset:
139 * @ctx: the user data (XML parser context)
140 * @name: the root element name
141 * @ExternalID: the external ID
142 * @SystemID: the SYSTEM ID (e.g. filename or URL)
143 *
144 * Callback on internal subset declaration.
145 */
146void
147internalSubset(void *ctx, const xmlChar *name,
148 const xmlChar *ExternalID, const xmlChar *SystemID)
149{
150 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
151 xmlDtdPtr dtd;
152#ifdef DEBUG_SAX
153 xmlGenericError(xmlGenericErrorContext,
154 "SAX.internalSubset(%s, %s, %s)\n",
155 name, ExternalID, SystemID);
156#endif
157
158 if (ctxt->myDoc == NULL)
159 return;
160 dtd = xmlGetIntSubset(ctxt->myDoc);
161 if (dtd != NULL) {
162 if (ctxt->html)
163 return;
164 xmlUnlinkNode((xmlNodePtr) dtd);
165 xmlFreeDtd(dtd);
166 ctxt->myDoc->intSubset = NULL;
167 }
168 ctxt->myDoc->intSubset =
169 xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
170}
171
172/**
173 * externalSubset:
174 * @ctx: the user data (XML parser context)
175 * @name: the root element name
176 * @ExternalID: the external ID
177 * @SystemID: the SYSTEM ID (e.g. filename or URL)
178 *
179 * Callback on external subset declaration.
180 */
181void
182externalSubset(void *ctx, const xmlChar *name,
183 const xmlChar *ExternalID, const xmlChar *SystemID)
184{
185 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
186#ifdef DEBUG_SAX
187 xmlGenericError(xmlGenericErrorContext,
188 "SAX.externalSubset(%s, %s, %s)\n",
189 name, ExternalID, SystemID);
190#endif
191 if (((ExternalID != NULL) || (SystemID != NULL)) &&
Daniel Veillard9403a042001-05-28 11:00:53 +0000192 (((ctxt->validate) || (ctxt->loadsubset != 0)) &&
Owen Taylor3473f882001-02-23 17:55:21 +0000193 (ctxt->wellFormed && ctxt->myDoc))) {
194 /*
195 * Try to fetch and parse the external subset.
196 */
197 xmlParserInputPtr oldinput;
198 int oldinputNr;
199 int oldinputMax;
200 xmlParserInputPtr *oldinputTab;
Owen Taylor3473f882001-02-23 17:55:21 +0000201 xmlParserInputPtr input = NULL;
202 xmlCharEncoding enc;
203 int oldcharset;
204
205 /*
206 * Ask the Entity resolver to load the damn thing
207 */
208 if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
209 input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID,
210 SystemID);
211 if (input == NULL) {
212 return;
213 }
214
215 xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID);
216
217 /*
218 * make sure we won't destroy the main document context
219 */
220 oldinput = ctxt->input;
221 oldinputNr = ctxt->inputNr;
222 oldinputMax = ctxt->inputMax;
223 oldinputTab = ctxt->inputTab;
Owen Taylor3473f882001-02-23 17:55:21 +0000224 oldcharset = ctxt->charset;
225
226 ctxt->inputTab = (xmlParserInputPtr *)
227 xmlMalloc(5 * sizeof(xmlParserInputPtr));
228 if (ctxt->inputTab == NULL) {
229 ctxt->errNo = XML_ERR_NO_MEMORY;
230 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
231 ctxt->sax->error(ctxt->userData,
232 "externalSubset: out of memory\n");
233 ctxt->errNo = XML_ERR_NO_MEMORY;
234 ctxt->input = oldinput;
235 ctxt->inputNr = oldinputNr;
236 ctxt->inputMax = oldinputMax;
237 ctxt->inputTab = oldinputTab;
238 ctxt->charset = oldcharset;
239 return;
240 }
241 ctxt->inputNr = 0;
242 ctxt->inputMax = 5;
243 ctxt->input = NULL;
244 xmlPushInput(ctxt, input);
245
246 /*
247 * On the fly encoding conversion if needed
248 */
249 enc = xmlDetectCharEncoding(ctxt->input->cur, 4);
250 xmlSwitchEncoding(ctxt, enc);
251
252 if (input->filename == NULL)
253 input->filename = (char *) xmlStrdup(SystemID);
254 input->line = 1;
255 input->col = 1;
256 input->base = ctxt->input->cur;
257 input->cur = ctxt->input->cur;
258 input->free = NULL;
259
260 /*
261 * let's parse that entity knowing it's an external subset.
262 */
263 xmlParseExternalSubset(ctxt, ExternalID, SystemID);
264
265 /*
266 * Free up the external entities
267 */
268
269 while (ctxt->inputNr > 1)
270 xmlPopInput(ctxt);
271 xmlFreeInputStream(ctxt->input);
272 xmlFree(ctxt->inputTab);
273
274 /*
275 * Restore the parsing context of the main entity
276 */
277 ctxt->input = oldinput;
278 ctxt->inputNr = oldinputNr;
279 ctxt->inputMax = oldinputMax;
280 ctxt->inputTab = oldinputTab;
281 ctxt->charset = oldcharset;
282 /* ctxt->wellFormed = oldwellFormed; */
283 }
284}
285
286/**
287 * resolveEntity:
288 * @ctx: the user data (XML parser context)
289 * @publicId: The public ID of the entity
290 * @systemId: The system ID of the entity
291 *
292 * The entity loader, to control the loading of external entities,
293 * the application can either:
294 * - override this resolveEntity() callback in the SAX block
295 * - or better use the xmlSetExternalEntityLoader() function to
296 * set up it's own entity resolution routine
297 *
298 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
299 */
300xmlParserInputPtr
301resolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
302{
303 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
304 xmlParserInputPtr ret;
305 xmlChar *URI;
306 const char *base = NULL;
307
308 if (ctxt->input != NULL)
309 base = ctxt->input->filename;
310 if (base == NULL)
311 base = ctxt->directory;
312
313 URI = xmlBuildURI(systemId, (const xmlChar *) base);
314
315#ifdef DEBUG_SAX
316 xmlGenericError(xmlGenericErrorContext,
317 "SAX.resolveEntity(%s, %s)\n", publicId, systemId);
318#endif
319
320 ret = xmlLoadExternalEntity((const char *) URI,
321 (const char *) publicId, ctxt);
322 if (URI != NULL)
323 xmlFree(URI);
324 return(ret);
325}
326
327/**
328 * getEntity:
329 * @ctx: the user data (XML parser context)
330 * @name: The entity name
331 *
332 * Get an entity by name
333 *
334 * Returns the xmlEntityPtr if found.
335 */
336xmlEntityPtr
337getEntity(void *ctx, const xmlChar *name)
338{
339 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
340 xmlEntityPtr ret;
341
342#ifdef DEBUG_SAX
343 xmlGenericError(xmlGenericErrorContext,
344 "SAX.getEntity(%s)\n", name);
345#endif
346
347 ret = xmlGetDocEntity(ctxt->myDoc, name);
348 if ((ret != NULL) && (ctxt->validate) && (ret->children == NULL) &&
349 (ret->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
350 /*
351 * for validation purposes we really need to fetch and
352 * parse the external entity
353 */
Owen Taylor3473f882001-02-23 17:55:21 +0000354 xmlNodePtr children;
355
Daniel Veillard5015b712001-08-17 09:37:52 +0000356 xmlParseCtxtExternalEntity(ctxt, ret->URI, ret->ExternalID, &children);
Owen Taylor3473f882001-02-23 17:55:21 +0000357 xmlAddChildList((xmlNodePtr) ret, children);
358 }
359 return(ret);
360}
361
362/**
363 * getParameterEntity:
364 * @ctx: the user data (XML parser context)
365 * @name: The entity name
366 *
367 * Get a parameter entity by name
368 *
369 * Returns the xmlEntityPtr if found.
370 */
371xmlEntityPtr
372getParameterEntity(void *ctx, const xmlChar *name)
373{
374 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
375 xmlEntityPtr ret;
376
377#ifdef DEBUG_SAX
378 xmlGenericError(xmlGenericErrorContext,
379 "SAX.getParameterEntity(%s)\n", name);
380#endif
381
382 ret = xmlGetParameterEntity(ctxt->myDoc, name);
383 return(ret);
384}
385
386
387/**
388 * entityDecl:
389 * @ctx: the user data (XML parser context)
390 * @name: the entity name
391 * @type: the entity type
392 * @publicId: The public ID of the entity
393 * @systemId: The system ID of the entity
394 * @content: the entity value (without processing).
395 *
396 * An entity definition has been parsed
397 */
398void
399entityDecl(void *ctx, const xmlChar *name, int type,
400 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
401{
402 xmlEntityPtr ent;
403 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
404
405#ifdef DEBUG_SAX
406 xmlGenericError(xmlGenericErrorContext,
407 "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
408 name, type, publicId, systemId, content);
409#endif
410 if (ctxt->inSubset == 1) {
411 ent = xmlAddDocEntity(ctxt->myDoc, name, type, publicId,
412 systemId, content);
413 if ((ent == NULL) && (ctxt->pedantic) &&
414 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
415 ctxt->sax->warning(ctxt,
416 "Entity(%s) already defined in the internal subset\n", name);
417 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
418 xmlChar *URI;
419 const char *base = NULL;
420
421 if (ctxt->input != NULL)
422 base = ctxt->input->filename;
423 if (base == NULL)
424 base = ctxt->directory;
425
426 URI = xmlBuildURI(systemId, (const xmlChar *) base);
427 ent->URI = URI;
428 }
429 } else if (ctxt->inSubset == 2) {
430 ent = xmlAddDtdEntity(ctxt->myDoc, name, type, publicId,
431 systemId, content);
432 if ((ent == NULL) && (ctxt->pedantic) &&
433 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
434 ctxt->sax->warning(ctxt,
435 "Entity(%s) already defined in the external subset\n", name);
436 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
437 xmlChar *URI;
438 const char *base = NULL;
439
440 if (ctxt->input != NULL)
441 base = ctxt->input->filename;
442 if (base == NULL)
443 base = ctxt->directory;
444
445 URI = xmlBuildURI(systemId, (const xmlChar *) base);
446 ent->URI = URI;
447 }
448 } else {
449 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
450 ctxt->sax->error(ctxt,
451 "SAX.entityDecl(%s) called while not in subset\n", name);
452 }
453}
454
455/**
456 * attributeDecl:
457 * @ctx: the user data (XML parser context)
458 * @elem: the name of the element
459 * @fullname: the attribute name
460 * @type: the attribute type
461 * @def: the type of default value
462 * @defaultValue: the attribute default value
463 * @tree: the tree of enumerated value set
464 *
465 * An attribute definition has been parsed
466 */
467void
468attributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname,
469 int type, int def, const xmlChar *defaultValue,
470 xmlEnumerationPtr tree)
471{
472 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
473 xmlAttributePtr attr;
474 xmlChar *name = NULL, *prefix = NULL;
475
476#ifdef DEBUG_SAX
477 xmlGenericError(xmlGenericErrorContext,
478 "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
479 elem, fullname, type, def, defaultValue);
480#endif
481 name = xmlSplitQName(ctxt, fullname, &prefix);
482 if (ctxt->inSubset == 1)
483 attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
484 name, prefix, (xmlAttributeType) type,
485 (xmlAttributeDefault) def, defaultValue, tree);
486 else if (ctxt->inSubset == 2)
487 attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, elem,
488 name, prefix, (xmlAttributeType) type,
489 (xmlAttributeDefault) def, defaultValue, tree);
490 else {
491 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
492 ctxt->sax->error(ctxt,
493 "SAX.attributeDecl(%s) called while not in subset\n", name);
494 return;
495 }
496 if (attr == 0) ctxt->valid = 0;
497 if (ctxt->validate && ctxt->wellFormed &&
498 ctxt->myDoc && ctxt->myDoc->intSubset)
499 ctxt->valid &= xmlValidateAttributeDecl(&ctxt->vctxt, ctxt->myDoc,
500 attr);
501 if (prefix != NULL)
502 xmlFree(prefix);
503 if (name != NULL)
504 xmlFree(name);
505}
506
507/**
508 * elementDecl:
509 * @ctx: the user data (XML parser context)
510 * @name: the element name
511 * @type: the element type
512 * @content: the element value tree
513 *
514 * An element definition has been parsed
515 */
516void
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000517elementDecl(void *ctx, const xmlChar * name, int type,
518 xmlElementContentPtr content)
Owen Taylor3473f882001-02-23 17:55:21 +0000519{
520 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
521 xmlElementPtr elem = NULL;
522
523#ifdef DEBUG_SAX
524 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000525 "SAX.elementDecl(%s, %d, ...)\n", name, type);
Owen Taylor3473f882001-02-23 17:55:21 +0000526#endif
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000527
Owen Taylor3473f882001-02-23 17:55:21 +0000528 if (ctxt->inSubset == 1)
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000529 elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset,
530 name, (xmlElementTypeVal) type, content);
Owen Taylor3473f882001-02-23 17:55:21 +0000531 else if (ctxt->inSubset == 2)
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000532 elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->extSubset,
533 name, (xmlElementTypeVal) type, content);
Owen Taylor3473f882001-02-23 17:55:21 +0000534 else {
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000535 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
536 ctxt->sax->error(ctxt,
537 "SAX.elementDecl(%s) called while not in subset\n",
538 name);
539 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000540 }
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000541 if (elem == NULL)
542 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000543 if (ctxt->validate && ctxt->wellFormed &&
544 ctxt->myDoc && ctxt->myDoc->intSubset)
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000545 ctxt->valid &=
546 xmlValidateElementDecl(&ctxt->vctxt, ctxt->myDoc, elem);
Owen Taylor3473f882001-02-23 17:55:21 +0000547}
548
549/**
550 * notationDecl:
551 * @ctx: the user data (XML parser context)
552 * @name: The name of the notation
553 * @publicId: The public ID of the entity
554 * @systemId: The system ID of the entity
555 *
556 * What to do when a notation declaration has been parsed.
557 */
558void
559notationDecl(void *ctx, const xmlChar *name,
560 const xmlChar *publicId, const xmlChar *systemId)
561{
562 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
563 xmlNotationPtr nota = NULL;
564
565#ifdef DEBUG_SAX
566 xmlGenericError(xmlGenericErrorContext,
567 "SAX.notationDecl(%s, %s, %s)\n", name, publicId, systemId);
568#endif
569
570 if (ctxt->inSubset == 1)
571 nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
572 publicId, systemId);
573 else if (ctxt->inSubset == 2)
Daniel Veillard25239c12001-03-14 13:56:48 +0000574 nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, name,
Owen Taylor3473f882001-02-23 17:55:21 +0000575 publicId, systemId);
576 else {
577 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
578 ctxt->sax->error(ctxt,
579 "SAX.notationDecl(%s) called while not in subset\n", name);
580 return;
581 }
582 if (nota == NULL) ctxt->valid = 0;
583 if (ctxt->validate && ctxt->wellFormed &&
584 ctxt->myDoc && ctxt->myDoc->intSubset)
585 ctxt->valid &= xmlValidateNotationDecl(&ctxt->vctxt, ctxt->myDoc,
586 nota);
587}
588
589/**
590 * unparsedEntityDecl:
591 * @ctx: the user data (XML parser context)
592 * @name: The name of the entity
593 * @publicId: The public ID of the entity
594 * @systemId: The system ID of the entity
595 * @notationName: the name of the notation
596 *
597 * What to do when an unparsed entity declaration is parsed
598 */
599void
600unparsedEntityDecl(void *ctx, const xmlChar *name,
601 const xmlChar *publicId, const xmlChar *systemId,
602 const xmlChar *notationName)
603{
Daniel Veillard9f4eb912001-08-01 21:22:27 +0000604 xmlEntityPtr ent;
Owen Taylor3473f882001-02-23 17:55:21 +0000605 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
606#ifdef DEBUG_SAX
607 xmlGenericError(xmlGenericErrorContext,
608 "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
609 name, publicId, systemId, notationName);
610#endif
611 if (ctxt->validate && ctxt->wellFormed &&
Daniel Veillarde020c3a2001-03-21 18:06:15 +0000612 ctxt->myDoc && ctxt->myDoc->extSubset)
Owen Taylor3473f882001-02-23 17:55:21 +0000613 ctxt->valid &= xmlValidateNotationUse(&ctxt->vctxt, ctxt->myDoc,
614 notationName);
Daniel Veillard9f4eb912001-08-01 21:22:27 +0000615 if (ctxt->inSubset == 1) {
616 ent = xmlAddDocEntity(ctxt->myDoc, name,
Daniel Veillarde020c3a2001-03-21 18:06:15 +0000617 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
618 publicId, systemId, notationName);
Daniel Veillard9f4eb912001-08-01 21:22:27 +0000619 if ((ent == NULL) && (ctxt->pedantic) &&
620 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
621 ctxt->sax->warning(ctxt,
622 "Entity(%s) already defined in the internal subset\n", name);
623 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
624 xmlChar *URI;
625 const char *base = NULL;
626
627 if (ctxt->input != NULL)
628 base = ctxt->input->filename;
629 if (base == NULL)
630 base = ctxt->directory;
631
632 URI = xmlBuildURI(systemId, (const xmlChar *) base);
633 ent->URI = URI;
634 }
635 } else if (ctxt->inSubset == 2) {
636 ent = xmlAddDtdEntity(ctxt->myDoc, name,
Daniel Veillarde020c3a2001-03-21 18:06:15 +0000637 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
638 publicId, systemId, notationName);
Daniel Veillard9f4eb912001-08-01 21:22:27 +0000639 if ((ent == NULL) && (ctxt->pedantic) &&
640 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
641 ctxt->sax->warning(ctxt,
642 "Entity(%s) already defined in the external subset\n", name);
643 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
644 xmlChar *URI;
645 const char *base = NULL;
646
647 if (ctxt->input != NULL)
648 base = ctxt->input->filename;
649 if (base == NULL)
650 base = ctxt->directory;
651
652 URI = xmlBuildURI(systemId, (const xmlChar *) base);
653 ent->URI = URI;
654 }
655 } else {
Daniel Veillarde020c3a2001-03-21 18:06:15 +0000656 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
657 ctxt->sax->error(ctxt,
658 "SAX.unparsedEntityDecl(%s) called while not in subset\n", name);
659 }
Owen Taylor3473f882001-02-23 17:55:21 +0000660}
661
662/**
663 * setDocumentLocator:
664 * @ctx: the user data (XML parser context)
665 * @loc: A SAX Locator
666 *
667 * Receive the document locator at startup, actually xmlDefaultSAXLocator
668 * Everything is available on the context, so this is useless in our case.
669 */
670void
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000671setDocumentLocator(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
Owen Taylor3473f882001-02-23 17:55:21 +0000672{
673 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
674#ifdef DEBUG_SAX
675 xmlGenericError(xmlGenericErrorContext,
676 "SAX.setDocumentLocator()\n");
677#endif
678}
679
680/**
681 * startDocument:
682 * @ctx: the user data (XML parser context)
683 *
684 * called when the document start being processed.
685 */
686void
687startDocument(void *ctx)
688{
689 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
690 xmlDocPtr doc;
691
692#ifdef DEBUG_SAX
693 xmlGenericError(xmlGenericErrorContext,
694 "SAX.startDocument()\n");
695#endif
696 if (ctxt->html) {
697 if (ctxt->myDoc == NULL)
698#ifdef LIBXML_HTML_ENABLED
699 ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL);
700#else
701 xmlGenericError(xmlGenericErrorContext,
702 "libxml2 built without HTML support\n");
703#endif
704 } else {
705 doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
706 if (doc != NULL) {
707 if (ctxt->encoding != NULL)
708 doc->encoding = xmlStrdup(ctxt->encoding);
709 else
710 doc->encoding = NULL;
711 doc->standalone = ctxt->standalone;
712 }
713 }
714 if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
715 (ctxt->input != NULL) && (ctxt->input->filename != NULL)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000716 ctxt->myDoc->URL = xmlStrdup((const xmlChar *) ctxt->input->filename);
Owen Taylor3473f882001-02-23 17:55:21 +0000717 }
718}
719
720/**
721 * endDocument:
722 * @ctx: the user data (XML parser context)
723 *
724 * called when the document end has been detected.
725 */
726void
727endDocument(void *ctx)
728{
729 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
730#ifdef DEBUG_SAX
731 xmlGenericError(xmlGenericErrorContext,
732 "SAX.endDocument()\n");
733#endif
734 if (ctxt->validate && ctxt->wellFormed &&
735 ctxt->myDoc && ctxt->myDoc->intSubset)
736 ctxt->valid &= xmlValidateDocumentFinal(&ctxt->vctxt, ctxt->myDoc);
737
738 /*
739 * Grab the encoding if it was added on-the-fly
740 */
741 if ((ctxt->encoding != NULL) && (ctxt->myDoc != NULL) &&
742 (ctxt->myDoc->encoding == NULL)) {
743 ctxt->myDoc->encoding = ctxt->encoding;
744 ctxt->encoding = NULL;
745 }
746 if ((ctxt->inputTab[0]->encoding != NULL) && (ctxt->myDoc != NULL) &&
747 (ctxt->myDoc->encoding == NULL)) {
748 ctxt->myDoc->encoding = xmlStrdup(ctxt->inputTab[0]->encoding);
749 }
750 if ((ctxt->charset != XML_CHAR_ENCODING_NONE) && (ctxt->myDoc != NULL) &&
751 (ctxt->myDoc->charset == XML_CHAR_ENCODING_NONE)) {
752 ctxt->myDoc->charset = ctxt->charset;
753 }
754}
755
756/**
757 * attribute:
758 * @ctx: the user data (XML parser context)
759 * @fullname: The attribute name, including namespace prefix
760 * @value: The attribute value
761 *
762 * Handle an attribute that has been read by the parser.
763 * The default handling is to convert the attribute into an
764 * DOM subtree and past it in a new xmlAttr element added to
765 * the element.
766 */
767void
768attribute(void *ctx, const xmlChar *fullname, const xmlChar *value)
769{
770 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
771 xmlAttrPtr ret;
772 xmlChar *name;
773 xmlChar *ns;
774 xmlChar *nval;
775 xmlNsPtr namespace;
776
777/****************
778#ifdef DEBUG_SAX
779 xmlGenericError(xmlGenericErrorContext,
780 "SAX.attribute(%s, %s)\n", fullname, value);
781#endif
782 ****************/
783 /*
784 * Split the full name into a namespace prefix and the tag name
785 */
786 name = xmlSplitQName(ctxt, fullname, &ns);
787
788 /*
789 * Do the last stage of the attribute normalization
790 * Needed for HTML too:
791 * http://www.w3.org/TR/html4/types.html#h-6.2
792 */
793 nval = xmlValidNormalizeAttributeValue(ctxt->myDoc, ctxt->node,
794 fullname, value);
795 if (nval != NULL)
796 value = nval;
797
798 /*
799 * Check whether it's a namespace definition
800 */
801 if ((!ctxt->html) && (ns == NULL) &&
802 (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
803 (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
804 if (value[0] != 0) {
805 xmlURIPtr uri;
806
807 uri = xmlParseURI((const char *)value);
808 if (uri == NULL) {
809 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
810 ctxt->sax->warning(ctxt->userData,
811 "nmlns: %s not a valid URI\n", value);
812 } else {
813 if (uri->scheme == NULL) {
814 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
815 ctxt->sax->warning(ctxt->userData,
816 "nmlns: URI %s is not absolute\n", value);
817 }
818 xmlFreeURI(uri);
819 }
820 }
821
822 /* a default namespace definition */
823 xmlNewNs(ctxt->node, value, NULL);
824 if (name != NULL)
825 xmlFree(name);
826 if (nval != NULL)
827 xmlFree(nval);
828 return;
829 }
830 if ((!ctxt->html) &&
831 (ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
832 (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
833 /*
834 * Validate also for namespace decls, they are attributes from
835 * an XML-1.0 perspective
836 TODO ... doesn't map well with current API
837 if (ctxt->validate && ctxt->wellFormed &&
838 ctxt->myDoc && ctxt->myDoc->intSubset)
839 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
840 ctxt->node, ret, value);
841 */
842 /* a standard namespace definition */
843 xmlNewNs(ctxt->node, value, name);
844 xmlFree(ns);
845 if (name != NULL)
846 xmlFree(name);
847 if (nval != NULL)
848 xmlFree(nval);
849 return;
850 }
851
852 if (ns != NULL)
853 namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, ns);
854 else {
855 namespace = NULL;
856 }
857
858 /* !!!!!! <a toto:arg="" xmlns:toto="http://toto.com"> */
859 ret = xmlNewNsProp(ctxt->node, namespace, name, NULL);
860
861 if (ret != NULL) {
862 if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
863 xmlNodePtr tmp;
864
865 ret->children = xmlStringGetNodeList(ctxt->myDoc, value);
866 tmp = ret->children;
867 while (tmp != NULL) {
868 tmp->parent = (xmlNodePtr) ret;
869 if (tmp->next == NULL)
870 ret->last = tmp;
871 tmp = tmp->next;
872 }
873 } else if (value != NULL) {
874 ret->children = xmlNewDocText(ctxt->myDoc, value);
875 ret->last = ret->children;
876 if (ret->children != NULL)
877 ret->children->parent = (xmlNodePtr) ret;
878 }
879 }
880
881 if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed &&
882 ctxt->myDoc && ctxt->myDoc->intSubset) {
883
884 /*
885 * If we don't substitute entities, the validation should be
886 * done on a value with replaced entities anyway.
887 */
888 if (!ctxt->replaceEntities) {
889 xmlChar *val;
890
891 ctxt->depth++;
892 val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
893 0,0,0);
894 ctxt->depth--;
895 if (val == NULL)
896 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
897 ctxt->myDoc, ctxt->node, ret, value);
898 else {
899 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
900 ctxt->myDoc, ctxt->node, ret, val);
901 xmlFree(val);
902 }
903 } else {
904 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
905 ctxt->node, ret, value);
906 }
Daniel Veillard62f313b2001-07-04 19:49:14 +0000907 } else if (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) ||
908 ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0))) {
Owen Taylor3473f882001-02-23 17:55:21 +0000909 /*
910 * when validating, the ID registration is done at the attribute
911 * validation level. Otherwise we have to do specific handling here.
912 */
913 if (xmlIsID(ctxt->myDoc, ctxt->node, ret))
914 xmlAddID(&ctxt->vctxt, ctxt->myDoc, value, ret);
915 else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret))
916 xmlAddRef(&ctxt->vctxt, ctxt->myDoc, value, ret);
917 }
918
919 if (nval != NULL)
920 xmlFree(nval);
921 if (name != NULL)
922 xmlFree(name);
923 if (ns != NULL)
924 xmlFree(ns);
925}
926
927/**
928 * startElement:
929 * @ctx: the user data (XML parser context)
930 * @fullname: The element name, including namespace prefix
931 * @atts: An array of name/value attributes pairs, NULL terminated
932 *
933 * called when an opening tag has been processed.
934 */
935void
936startElement(void *ctx, const xmlChar *fullname, const xmlChar **atts)
937{
938 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
939 xmlNodePtr ret;
940 xmlNodePtr parent = ctxt->node;
941 xmlNsPtr ns;
942 xmlChar *name;
943 xmlChar *prefix;
944 const xmlChar *att;
945 const xmlChar *value;
946 int i;
947
948#ifdef DEBUG_SAX
949 xmlGenericError(xmlGenericErrorContext,
950 "SAX.startElement(%s)\n", fullname);
951#endif
952
953 /*
954 * First check on validity:
955 */
956 if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) &&
957 ((ctxt->myDoc->intSubset == NULL) ||
958 ((ctxt->myDoc->intSubset->notations == NULL) &&
959 (ctxt->myDoc->intSubset->elements == NULL) &&
960 (ctxt->myDoc->intSubset->attributes == NULL) &&
961 (ctxt->myDoc->intSubset->entities == NULL)))) {
962 if (ctxt->vctxt.error != NULL) {
963 ctxt->vctxt.error(ctxt->vctxt.userData,
964 "Validation failed: no DTD found !\n");
965 }
966 ctxt->validate = 0;
Daniel Veillard7a51d6d2001-09-10 14:40:43 +0000967 ctxt->valid = 0;
968 ctxt->errNo = XML_ERR_NO_DTD;
Owen Taylor3473f882001-02-23 17:55:21 +0000969 }
970
971
972 /*
973 * Split the full name into a namespace prefix and the tag name
974 */
975 name = xmlSplitQName(ctxt, fullname, &prefix);
976
977
978 /*
979 * Note : the namespace resolution is deferred until the end of the
980 * attributes parsing, since local namespace can be defined as
981 * an attribute at this level.
982 */
983 ret = xmlNewDocNode(ctxt->myDoc, NULL, name, NULL);
984 if (ret == NULL) return;
985 if (ctxt->myDoc->children == NULL) {
986#ifdef DEBUG_SAX_TREE
987 xmlGenericError(xmlGenericErrorContext, "Setting %s as root\n", name);
988#endif
989 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
990 } else if (parent == NULL) {
991 parent = ctxt->myDoc->children;
992 }
993 ctxt->nodemem = -1;
Daniel Veillardd9bad132001-07-23 19:39:43 +0000994 if (ctxt->linenumbers) {
995 if (ctxt->input != NULL)
996 ret->content = (void *) (long) ctxt->input->line;
997 }
Owen Taylor3473f882001-02-23 17:55:21 +0000998
999 /*
1000 * We are parsing a new node.
1001 */
1002#ifdef DEBUG_SAX_TREE
1003 xmlGenericError(xmlGenericErrorContext, "pushing(%s)\n", name);
1004#endif
1005 nodePush(ctxt, ret);
1006
1007 /*
1008 * Link the child element
1009 */
1010 if (parent != NULL) {
1011 if (parent->type == XML_ELEMENT_NODE) {
1012#ifdef DEBUG_SAX_TREE
1013 xmlGenericError(xmlGenericErrorContext,
1014 "adding child %s to %s\n", name, parent->name);
1015#endif
1016 xmlAddChild(parent, ret);
1017 } else {
1018#ifdef DEBUG_SAX_TREE
1019 xmlGenericError(xmlGenericErrorContext,
1020 "adding sibling %s to ", name);
1021 xmlDebugDumpOneNode(stderr, parent, 0);
1022#endif
1023 xmlAddSibling(parent, ret);
1024 }
1025 }
1026
1027 /*
Daniel Veillard48da9102001-08-07 01:10:10 +00001028 * Insert all the defaulted attributes from the DTD especially namespaces
1029 */
1030 if ((!ctxt->html) &&
1031 ((ctxt->myDoc->intSubset != NULL) ||
1032 (ctxt->myDoc->extSubset != NULL))) {
1033 xmlElementPtr elemDecl = NULL;
1034
1035 if (prefix != NULL) {
1036 if (ctxt->myDoc->intSubset != NULL)
1037 elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->intSubset,
1038 name, prefix);
1039 if ((elemDecl == NULL) && (ctxt->myDoc->extSubset != NULL))
1040 elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->extSubset,
1041 name, prefix);
1042 } else {
1043 if (ctxt->myDoc->intSubset != NULL)
1044 elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->intSubset,
1045 name, prefix);
1046 if ((elemDecl == NULL) && (ctxt->myDoc->extSubset != NULL))
1047 elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->extSubset,
1048 name, prefix);
1049 }
1050 if (elemDecl != NULL) {
1051 xmlAttributePtr attr = elemDecl->attributes;
1052 while (attr != NULL) {
1053 if (attr->defaultValue != NULL) {
1054 /*
1055 * the element should be instanciated in the tree if:
1056 * - this is a namespace prefix
1057 * - the user required for completion in the tree
1058 * like XSLT
1059 */
1060 if (((attr->prefix != NULL) &&
1061 (xmlStrEqual(attr->prefix, BAD_CAST "xmlns"))) ||
1062 ((attr->prefix == NULL) &&
1063 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) ||
1064 (ctxt->loadsubset & XML_COMPLETE_ATTRS)) {
1065 xmlChar buffer[100];
1066 const xmlChar *fulln = attr->name;
1067
1068 if (attr->prefix != NULL) {
1069 snprintf((char *) buffer, 99, "%s:%s",
1070 attr->prefix, attr->name);
1071 buffer[99] = 0;
1072 fulln = buffer;
1073 }
1074
1075 /*
1076 * Check that the attribute is not declared in the
1077 * serialization
1078 */
1079 att = NULL;
1080 if (atts != NULL) {
1081 i = 0;
1082 att = atts[i];
1083 while (att != NULL) {
1084 if (xmlStrEqual(att, fulln))
1085 break;
1086 i += 2;
1087 att = atts[i];
1088 }
1089 }
1090 if (att == NULL)
1091 attribute(ctxt, fulln, attr->defaultValue);
1092 }
1093 }
1094 attr = attr->nexth;
1095 }
1096 }
1097 }
1098
1099 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001100 * process all the attributes whose name start with "xml"
1101 */
1102 if (atts != NULL) {
1103 i = 0;
1104 att = atts[i++];
1105 value = atts[i++];
1106 if (!ctxt->html) {
1107 while ((att != NULL) && (value != NULL)) {
1108 if ((att[0] == 'x') && (att[1] == 'm') && (att[2] == 'l'))
1109 attribute(ctxt, att, value);
1110
1111 att = atts[i++];
1112 value = atts[i++];
1113 }
1114 }
1115 }
1116
1117 /*
1118 * Search the namespace, note that since the attributes have been
1119 * processed, the local namespaces are available.
1120 */
1121 ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
1122 if ((ns == NULL) && (parent != NULL))
1123 ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
1124 if ((prefix != NULL) && (ns == NULL)) {
1125 ns = xmlNewNs(ret, NULL, prefix);
1126 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1127 ctxt->sax->warning(ctxt->userData,
1128 "Namespace prefix %s is not defined\n", prefix);
1129 }
Daniel Veillard143b04f2001-09-10 18:14:14 +00001130
1131 /*
1132 * set the namespace node, making sure that if the default namspace
1133 * is unbound on a parent we simply kee it NULL
1134 */
Daniel Veillard651f9472001-10-04 14:51:06 +00001135 if ((ns != NULL) && (ns->href != NULL) && (ns->href[0] != 0))
Daniel Veillard143b04f2001-09-10 18:14:14 +00001136 xmlSetNs(ret, ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001137
1138 /*
1139 * process all the other attributes
1140 */
1141 if (atts != NULL) {
1142 i = 0;
1143 att = atts[i++];
1144 value = atts[i++];
1145 if (ctxt->html) {
1146 while (att != NULL) {
1147 attribute(ctxt, att, value);
1148 att = atts[i++];
1149 value = atts[i++];
1150 }
1151 } else {
1152 while ((att != NULL) && (value != NULL)) {
1153 if ((att[0] != 'x') || (att[1] != 'm') || (att[2] != 'l'))
1154 attribute(ctxt, att, value);
1155
1156 /*
1157 * Next ones
1158 */
1159 att = atts[i++];
1160 value = atts[i++];
1161 }
1162 }
1163 }
1164
1165 /*
1166 * If it's the Document root, finish the Dtd validation and
1167 * check the document root element for validity
1168 */
1169 if ((ctxt->validate) && (ctxt->vctxt.finishDtd == 0)) {
1170 ctxt->valid &= xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc);
1171 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
1172 ctxt->vctxt.finishDtd = 1;
1173 }
1174
1175 if (prefix != NULL)
1176 xmlFree(prefix);
1177 if (name != NULL)
1178 xmlFree(name);
1179
1180}
1181
1182/**
1183 * endElement:
1184 * @ctx: the user data (XML parser context)
1185 * @name: The element name
1186 *
1187 * called when the end of an element has been detected.
1188 */
1189void
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001190endElement(void *ctx, const xmlChar *name ATTRIBUTE_UNUSED)
Owen Taylor3473f882001-02-23 17:55:21 +00001191{
1192 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1193 xmlParserNodeInfo node_info;
1194 xmlNodePtr cur = ctxt->node;
1195
1196#ifdef DEBUG_SAX
1197 if (name == NULL)
1198 xmlGenericError(xmlGenericErrorContext, "SAX.endElement(NULL)\n");
1199 else
1200 xmlGenericError(xmlGenericErrorContext, "SAX.endElement(%s)\n", name);
1201#endif
1202
1203 /* Capture end position and add node */
1204 if (cur != NULL && ctxt->record_info) {
1205 node_info.end_pos = ctxt->input->cur - ctxt->input->base;
1206 node_info.end_line = ctxt->input->line;
1207 node_info.node = cur;
1208 xmlParserAddNodeInfo(ctxt, &node_info);
1209 }
1210 ctxt->nodemem = -1;
1211
1212 if (ctxt->validate && ctxt->wellFormed &&
1213 ctxt->myDoc && ctxt->myDoc->intSubset)
1214 ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc,
1215 cur);
1216
1217
1218 /*
1219 * end of parsing of this node.
1220 */
1221#ifdef DEBUG_SAX_TREE
1222 xmlGenericError(xmlGenericErrorContext, "popping(%s)\n", cur->name);
1223#endif
1224 nodePop(ctxt);
1225}
1226
1227/**
1228 * reference:
1229 * @ctx: the user data (XML parser context)
1230 * @name: The entity name
1231 *
1232 * called when an entity reference is detected.
1233 */
1234void
1235reference(void *ctx, const xmlChar *name)
1236{
1237 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1238 xmlNodePtr ret;
1239
1240#ifdef DEBUG_SAX
1241 xmlGenericError(xmlGenericErrorContext,
1242 "SAX.reference(%s)\n", name);
1243#endif
1244 if (name[0] == '#')
1245 ret = xmlNewCharRef(ctxt->myDoc, name);
1246 else
1247 ret = xmlNewReference(ctxt->myDoc, name);
1248#ifdef DEBUG_SAX_TREE
1249 xmlGenericError(xmlGenericErrorContext,
1250 "add reference %s to %s \n", name, ctxt->node->name);
1251#endif
1252 xmlAddChild(ctxt->node, ret);
1253}
1254
1255/**
1256 * characters:
1257 * @ctx: the user data (XML parser context)
1258 * @ch: a xmlChar string
1259 * @len: the number of xmlChar
1260 *
1261 * receiving some chars from the parser.
Owen Taylor3473f882001-02-23 17:55:21 +00001262 */
1263void
1264characters(void *ctx, const xmlChar *ch, int len)
1265{
1266 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1267 xmlNodePtr lastChild;
1268
1269#ifdef DEBUG_SAX
1270 xmlGenericError(xmlGenericErrorContext,
1271 "SAX.characters(%.30s, %d)\n", ch, len);
1272#endif
1273 /*
1274 * Handle the data if any. If there is no child
1275 * add it as content, otherwise if the last child is text,
1276 * concatenate it, else create a new node of type text.
1277 */
1278
1279 if (ctxt->node == NULL) {
1280#ifdef DEBUG_SAX_TREE
1281 xmlGenericError(xmlGenericErrorContext,
1282 "add chars: ctxt->node == NULL !\n");
1283#endif
1284 return;
1285 }
1286 lastChild = xmlGetLastChild(ctxt->node);
1287#ifdef DEBUG_SAX_TREE
1288 xmlGenericError(xmlGenericErrorContext,
1289 "add chars to %s \n", ctxt->node->name);
1290#endif
1291
1292 /*
1293 * Here we needed an accelerator mechanism in case of very large
1294 * elements. Use an attribute in the structure !!!
1295 */
1296 if (lastChild == NULL) {
1297 /* first node, first time */
1298 xmlNodeAddContentLen(ctxt->node, ch, len);
1299#ifndef XML_USE_BUFFER_CONTENT
1300 if (ctxt->node->children != NULL) {
1301 ctxt->nodelen = len;
1302 ctxt->nodemem = len + 1;
1303 }
1304#endif
1305 } else {
Daniel Veillardf300b7e2001-08-13 10:43:15 +00001306 int coalesceText = (lastChild != NULL) &&
1307 (lastChild->type == XML_TEXT_NODE) &&
1308 (lastChild->name == xmlStringText);
1309 if ((coalesceText) && (ctxt->nodemem != 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001310#ifndef XML_USE_BUFFER_CONTENT
1311 /*
1312 * The whole point of maintaining nodelen and nodemem,
Daniel Veillard60087f32001-10-10 09:45:09 +00001313 * xmlTextConcat is too costly, i.e. compute length,
Owen Taylor3473f882001-02-23 17:55:21 +00001314 * reallocate a new buffer, move data, append ch. Here
1315 * We try to minimaze realloc() uses and avoid copying
Daniel Veillard60087f32001-10-10 09:45:09 +00001316 * and recomputing length over and over.
Owen Taylor3473f882001-02-23 17:55:21 +00001317 */
1318 if (ctxt->nodelen + len >= ctxt->nodemem) {
1319 xmlChar *newbuf;
1320 int size;
1321
1322 size = ctxt->nodemem + len;
1323 size *= 2;
1324 newbuf = (xmlChar *) xmlRealloc(lastChild->content,size);
1325 if (newbuf == NULL) {
1326 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1327 ctxt->sax->error(ctxt->userData,
1328 "SAX.characters(): out of memory\n");
1329 return;
1330 }
1331 ctxt->nodemem = size;
1332 lastChild->content = newbuf;
1333 }
1334 memcpy(&lastChild->content[ctxt->nodelen], ch, len);
1335 ctxt->nodelen += len;
1336 lastChild->content[ctxt->nodelen] = 0;
1337#else
1338 xmlTextConcat(lastChild, ch, len);
1339#endif
Daniel Veillardf300b7e2001-08-13 10:43:15 +00001340 } else if (coalesceText) {
Daniel Veillard80f32572001-03-07 19:45:40 +00001341 xmlTextConcat(lastChild, ch, len);
1342 if (ctxt->node->children != NULL) {
1343 ctxt->nodelen = xmlStrlen(lastChild->content);
1344 ctxt->nodemem = ctxt->nodelen + 1;
1345 }
Owen Taylor3473f882001-02-23 17:55:21 +00001346 } else {
1347 /* Mixed content, first time */
1348 lastChild = xmlNewTextLen(ch, len);
1349 xmlAddChild(ctxt->node, lastChild);
1350#ifndef XML_USE_BUFFER_CONTENT
1351 if (ctxt->node->children != NULL) {
1352 ctxt->nodelen = len;
1353 ctxt->nodemem = len + 1;
1354 }
1355#endif
1356 }
1357 }
1358}
1359
1360/**
1361 * ignorableWhitespace:
1362 * @ctx: the user data (XML parser context)
1363 * @ch: a xmlChar string
1364 * @len: the number of xmlChar
1365 *
1366 * receiving some ignorable whitespaces from the parser.
Daniel Veillard05c13a22001-09-09 08:38:09 +00001367 * UNUSED: by default the DOM building will use characters
Owen Taylor3473f882001-02-23 17:55:21 +00001368 */
1369void
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001370ignorableWhitespace(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch ATTRIBUTE_UNUSED, int len ATTRIBUTE_UNUSED)
Owen Taylor3473f882001-02-23 17:55:21 +00001371{
1372 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
1373#ifdef DEBUG_SAX
1374 xmlGenericError(xmlGenericErrorContext,
1375 "SAX.ignorableWhitespace(%.30s, %d)\n", ch, len);
1376#endif
1377}
1378
1379/**
1380 * processingInstruction:
1381 * @ctx: the user data (XML parser context)
1382 * @target: the target name
1383 * @data: the PI data's
1384 *
1385 * A processing instruction has been parsed.
1386 */
1387void
1388processingInstruction(void *ctx, const xmlChar *target,
1389 const xmlChar *data)
1390{
1391 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1392 xmlNodePtr ret;
1393 xmlNodePtr parent = ctxt->node;
1394
1395#ifdef DEBUG_SAX
1396 xmlGenericError(xmlGenericErrorContext,
1397 "SAX.processingInstruction(%s, %s)\n", target, data);
1398#endif
1399
1400 ret = xmlNewPI(target, data);
1401 if (ret == NULL) return;
1402 parent = ctxt->node;
1403
1404 if (ctxt->inSubset == 1) {
1405 xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
1406 return;
1407 } else if (ctxt->inSubset == 2) {
1408 xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
1409 return;
1410 }
1411 if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
1412#ifdef DEBUG_SAX_TREE
1413 xmlGenericError(xmlGenericErrorContext,
1414 "Setting PI %s as root\n", target);
1415#endif
1416 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
1417 return;
1418 }
1419 if (parent->type == XML_ELEMENT_NODE) {
1420#ifdef DEBUG_SAX_TREE
1421 xmlGenericError(xmlGenericErrorContext,
1422 "adding PI %s child to %s\n", target, parent->name);
1423#endif
1424 xmlAddChild(parent, ret);
1425 } else {
1426#ifdef DEBUG_SAX_TREE
1427 xmlGenericError(xmlGenericErrorContext,
1428 "adding PI %s sibling to ", target);
1429 xmlDebugDumpOneNode(stderr, parent, 0);
1430#endif
1431 xmlAddSibling(parent, ret);
1432 }
1433}
1434
1435/**
1436 * globalNamespace:
1437 * @ctx: the user data (XML parser context)
1438 * @href: the namespace associated URN
1439 * @prefix: the namespace prefix
1440 *
1441 * An old global namespace has been parsed.
1442 */
1443void
1444globalNamespace(void *ctx, const xmlChar *href, const xmlChar *prefix)
1445{
1446 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1447#ifdef DEBUG_SAX
1448 xmlGenericError(xmlGenericErrorContext,
1449 "SAX.globalNamespace(%s, %s)\n", href, prefix);
1450#endif
1451 xmlNewGlobalNs(ctxt->myDoc, href, prefix);
1452}
1453
1454/**
1455 * setNamespace:
1456 * @ctx: the user data (XML parser context)
1457 * @name: the namespace prefix
1458 *
1459 * Set the current element namespace.
1460 */
1461
1462void
1463setNamespace(void *ctx, const xmlChar *name)
1464{
1465 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1466 xmlNsPtr ns;
1467 xmlNodePtr parent;
1468
1469#ifdef DEBUG_SAX
1470 xmlGenericError(xmlGenericErrorContext, "SAX.setNamespace(%s)\n", name);
1471#endif
1472 ns = xmlSearchNs(ctxt->myDoc, ctxt->node, name);
1473 if (ns == NULL) { /* ctxt->node may not have a parent yet ! */
1474 if (ctxt->nodeNr >= 2) {
1475 parent = ctxt->nodeTab[ctxt->nodeNr - 2];
1476 if (parent != NULL)
1477 ns = xmlSearchNs(ctxt->myDoc, parent, name);
1478 }
1479 }
1480 xmlSetNs(ctxt->node, ns);
1481}
1482
1483/**
1484 * getNamespace:
1485 * @ctx: the user data (XML parser context)
1486 *
1487 * Get the current element namespace.
1488 *
1489 * Returns the xmlNsPtr or NULL if none
1490 */
1491
1492xmlNsPtr
1493getNamespace(void *ctx)
1494{
1495 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1496 xmlNsPtr ret;
1497
1498#ifdef DEBUG_SAX
1499 xmlGenericError(xmlGenericErrorContext, "SAX.getNamespace()\n");
1500#endif
1501 ret = ctxt->node->ns;
1502 return(ret);
1503}
1504
1505/**
1506 * checkNamespace:
1507 * @ctx: the user data (XML parser context)
1508 * @namespace: the namespace to check against
1509 *
1510 * Check that the current element namespace is the same as the
1511 * one read upon parsing.
1512 *
1513 * Returns 1 if true 0 otherwise
1514 */
1515
1516int
1517checkNamespace(void *ctx, xmlChar *namespace)
1518{
1519 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1520 xmlNodePtr cur = ctxt->node;
1521
1522#ifdef DEBUG_SAX
1523 xmlGenericError(xmlGenericErrorContext,
1524 "SAX.checkNamespace(%s)\n", namespace);
1525#endif
1526
1527 /*
1528 * Check that the Name in the ETag is the same as in the STag.
1529 */
1530 if (namespace == NULL) {
1531 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1532 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1533 ctxt->sax->error(ctxt,
1534 "End tags for %s don't hold the namespace %s\n",
1535 cur->name, cur->ns->prefix);
1536 ctxt->wellFormed = 0;
1537 }
1538 } else {
1539 if ((cur->ns == NULL) || (cur->ns->prefix == NULL)) {
1540 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1541 ctxt->sax->error(ctxt,
1542 "End tags %s holds a prefix %s not used by the open tag\n",
1543 cur->name, namespace);
1544 ctxt->wellFormed = 0;
1545 } else if (!xmlStrEqual(namespace, cur->ns->prefix)) {
1546 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1547 ctxt->sax->error(ctxt,
1548 "Start and End tags for %s don't use the same namespaces: %s and %s\n",
1549 cur->name, cur->ns->prefix, namespace);
1550 ctxt->wellFormed = 0;
1551 } else
1552 return(1);
1553 }
1554 return(0);
1555}
1556
1557/**
1558 * namespaceDecl:
1559 * @ctx: the user data (XML parser context)
1560 * @href: the namespace associated URN
1561 * @prefix: the namespace prefix
1562 *
1563 * A namespace has been parsed.
1564 */
1565void
1566namespaceDecl(void *ctx, const xmlChar *href, const xmlChar *prefix)
1567{
1568 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1569#ifdef DEBUG_SAX
1570 if (prefix == NULL)
1571 xmlGenericError(xmlGenericErrorContext,
1572 "SAX.namespaceDecl(%s, NULL)\n", href);
1573 else
1574 xmlGenericError(xmlGenericErrorContext,
1575 "SAX.namespaceDecl(%s, %s)\n", href, prefix);
1576#endif
1577 xmlNewNs(ctxt->node, href, prefix);
1578}
1579
1580/**
1581 * comment:
1582 * @ctx: the user data (XML parser context)
1583 * @value: the comment content
1584 *
1585 * A comment has been parsed.
1586 */
1587void
1588comment(void *ctx, const xmlChar *value)
1589{
1590 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1591 xmlNodePtr ret;
1592 xmlNodePtr parent = ctxt->node;
1593
1594#ifdef DEBUG_SAX
1595 xmlGenericError(xmlGenericErrorContext, "SAX.comment(%s)\n", value);
1596#endif
1597 ret = xmlNewDocComment(ctxt->myDoc, value);
1598 if (ret == NULL) return;
1599
1600 if (ctxt->inSubset == 1) {
1601 xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
1602 return;
1603 } else if (ctxt->inSubset == 2) {
1604 xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
1605 return;
1606 }
1607 if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
1608#ifdef DEBUG_SAX_TREE
1609 xmlGenericError(xmlGenericErrorContext,
1610 "Setting comment as root\n");
1611#endif
1612 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
1613 return;
1614 }
1615 if (parent->type == XML_ELEMENT_NODE) {
1616#ifdef DEBUG_SAX_TREE
1617 xmlGenericError(xmlGenericErrorContext,
1618 "adding comment child to %s\n", parent->name);
1619#endif
1620 xmlAddChild(parent, ret);
1621 } else {
1622#ifdef DEBUG_SAX_TREE
1623 xmlGenericError(xmlGenericErrorContext,
1624 "adding comment sibling to ");
1625 xmlDebugDumpOneNode(stderr, parent, 0);
1626#endif
1627 xmlAddSibling(parent, ret);
1628 }
1629}
1630
1631/**
1632 * cdataBlock:
1633 * @ctx: the user data (XML parser context)
1634 * @value: The pcdata content
1635 * @len: the block length
1636 *
1637 * called when a pcdata block has been parsed
1638 */
1639void
1640cdataBlock(void *ctx, const xmlChar *value, int len)
1641{
1642 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1643 xmlNodePtr ret, lastChild;
1644
1645#ifdef DEBUG_SAX
1646 xmlGenericError(xmlGenericErrorContext,
1647 "SAX.pcdata(%.10s, %d)\n", value, len);
1648#endif
1649 lastChild = xmlGetLastChild(ctxt->node);
1650#ifdef DEBUG_SAX_TREE
1651 xmlGenericError(xmlGenericErrorContext,
1652 "add chars to %s \n", ctxt->node->name);
1653#endif
1654 if ((lastChild != NULL) &&
1655 (lastChild->type == XML_CDATA_SECTION_NODE)) {
1656 xmlTextConcat(lastChild, value, len);
1657 } else {
1658 ret = xmlNewCDataBlock(ctxt->myDoc, value, len);
1659 xmlAddChild(ctxt->node, ret);
1660 }
1661}
1662
Daniel Veillardd0463562001-10-13 09:15:48 +00001663/**
1664 * xmlDefaultSAXHandlerInit:
1665 *
1666 * Initialize the default SAX handler
Owen Taylor3473f882001-02-23 17:55:21 +00001667 */
Daniel Veillardd0463562001-10-13 09:15:48 +00001668void
1669initxmlDefaultSAXHandler(xmlSAXHandler *hdlr, int warning)
1670{
1671 if(hdlr->initialized == 1)
1672 return;
1673
1674 hdlr->internalSubset = internalSubset;
1675 hdlr->externalSubset = externalSubset;
1676 hdlr->isStandalone = isStandalone;
1677 hdlr->hasInternalSubset = hasInternalSubset;
1678 hdlr->hasExternalSubset = hasExternalSubset;
1679 hdlr->resolveEntity = resolveEntity;
1680 hdlr->getEntity = getEntity;
1681 hdlr->getParameterEntity = getParameterEntity;
1682 hdlr->entityDecl = entityDecl;
1683 hdlr->attributeDecl = attributeDecl;
1684 hdlr->elementDecl = elementDecl;
1685 hdlr->notationDecl = notationDecl;
1686 hdlr->unparsedEntityDecl = unparsedEntityDecl;
1687 hdlr->setDocumentLocator = setDocumentLocator;
1688 hdlr->startDocument = startDocument;
1689 hdlr->endDocument = endDocument;
1690 hdlr->startElement = startElement;
1691 hdlr->endElement = endElement;
1692 hdlr->reference = reference;
1693 hdlr->characters = characters;
1694 hdlr->cdataBlock = cdataBlock;
1695 hdlr->ignorableWhitespace = characters;
1696 hdlr->processingInstruction = processingInstruction;
1697 hdlr->comment = comment;
1698 /* if (xmlGetWarningsDefaultValue == 0) */
1699 if (warning == 0)
1700 hdlr->warning = NULL;
1701 else
1702 hdlr->warning = xmlParserWarning;
1703 hdlr->error = xmlParserError;
1704 hdlr->fatalError = xmlParserError;
1705
1706 hdlr->initialized = 1;
1707}
Owen Taylor3473f882001-02-23 17:55:21 +00001708
1709/**
1710 * xmlDefaultSAXHandlerInit:
1711 *
1712 * Initialize the default SAX handler
1713 */
1714void
1715xmlDefaultSAXHandlerInit(void)
1716{
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001717 initxmlDefaultSAXHandler(&xmlDefaultSAXHandler, xmlGetWarningsDefaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001718}
1719
Daniel Veillardeae522a2001-04-23 13:41:34 +00001720#ifdef LIBXML_HTML_ENABLED
Daniel Veillardd0463562001-10-13 09:15:48 +00001721
1722/**
1723 * htmlDefaultSAXHandlerInit:
1724 *
1725 * Initialize the default SAX handler
Owen Taylor3473f882001-02-23 17:55:21 +00001726 */
Daniel Veillardd0463562001-10-13 09:15:48 +00001727void
1728inithtmlDefaultSAXHandler(xmlSAXHandler *hdlr)
1729{
1730 if(hdlr->initialized == 1)
1731 return;
1732
1733 hdlr->internalSubset = internalSubset;
1734 hdlr->externalSubset = NULL;
1735 hdlr->isStandalone = NULL;
1736 hdlr->hasInternalSubset = NULL;
1737 hdlr->hasExternalSubset = NULL;
1738 hdlr->resolveEntity = NULL;
1739 hdlr->getEntity = getEntity;
1740 hdlr->getParameterEntity = NULL;
1741 hdlr->entityDecl = NULL;
1742 hdlr->attributeDecl = NULL;
1743 hdlr->elementDecl = NULL;
1744 hdlr->notationDecl = NULL;
1745 hdlr->unparsedEntityDecl = NULL;
1746 hdlr->setDocumentLocator = setDocumentLocator;
1747 hdlr->startDocument = startDocument;
1748 hdlr->endDocument = endDocument;
1749 hdlr->startElement = startElement;
1750 hdlr->endElement = endElement;
1751 hdlr->reference = NULL;
1752 hdlr->characters = characters;
1753 hdlr->cdataBlock = cdataBlock;
1754 hdlr->ignorableWhitespace = ignorableWhitespace;
1755 hdlr->processingInstruction = NULL;
1756 hdlr->comment = comment;
1757 hdlr->warning = xmlParserWarning;
1758 hdlr->error = xmlParserError;
1759 hdlr->fatalError = xmlParserError;
1760
1761 hdlr->initialized = 1;
1762}
Owen Taylor3473f882001-02-23 17:55:21 +00001763
1764/**
1765 * htmlDefaultSAXHandlerInit:
1766 *
1767 * Initialize the default SAX handler
1768 */
1769void
1770htmlDefaultSAXHandlerInit(void)
1771{
Daniel Veillardd0463562001-10-13 09:15:48 +00001772 inithtmlDefaultSAXHandler(&htmlDefaultSAXHandler);
Owen Taylor3473f882001-02-23 17:55:21 +00001773}
Daniel Veillardd0463562001-10-13 09:15:48 +00001774
Daniel Veillardeae522a2001-04-23 13:41:34 +00001775#endif /* LIBXML_HTML_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001776
Daniel Veillardeae522a2001-04-23 13:41:34 +00001777#ifdef LIBXML_DOCB_ENABLED
Daniel Veillardd0463562001-10-13 09:15:48 +00001778
1779void
1780initdocbDefaultSAXHandler(xmlSAXHandler *hdlr)
1781{
1782 if(hdlr->initialized == 1)
1783 return;
1784
1785 hdlr->internalSubset = internalSubset;
1786 hdlr->externalSubset = NULL;
1787 hdlr->isStandalone = isStandalone;
1788 hdlr->hasInternalSubset = hasInternalSubset;
1789 hdlr->hasExternalSubset = hasExternalSubset;
1790 hdlr->resolveEntity = resolveEntity;
1791 hdlr->getEntity = getEntity;
1792 hdlr->getParameterEntity = NULL;
1793 hdlr->entityDecl = entityDecl;
1794 hdlr->attributeDecl = NULL;
1795 hdlr->elementDecl = NULL;
1796 hdlr->notationDecl = NULL;
1797 hdlr->unparsedEntityDecl = NULL;
1798 hdlr->setDocumentLocator = setDocumentLocator;
1799 hdlr->startDocument = startDocument;
1800 hdlr->endDocument = endDocument;
1801 hdlr->startElement = startElement;
1802 hdlr->endElement = endElement;
1803 hdlr->reference = reference;
1804 hdlr->characters = characters;
1805 hdlr->cdataBlock = NULL;
1806 hdlr->ignorableWhitespace = ignorableWhitespace;
1807 hdlr->processingInstruction = NULL;
1808 hdlr->comment = comment;
1809 hdlr->warning = xmlParserWarning;
1810 hdlr->error = xmlParserError;
1811 hdlr->fatalError = xmlParserError;
1812
1813 hdlr->initialized = 1;
1814}
Owen Taylor3473f882001-02-23 17:55:21 +00001815
1816/**
Daniel Veillardeae522a2001-04-23 13:41:34 +00001817 * docbDefaultSAXHandlerInit:
Owen Taylor3473f882001-02-23 17:55:21 +00001818 *
1819 * Initialize the default SAX handler
1820 */
1821void
Daniel Veillardeae522a2001-04-23 13:41:34 +00001822docbDefaultSAXHandlerInit(void)
Owen Taylor3473f882001-02-23 17:55:21 +00001823{
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001824 initdocbDefaultSAXHandler(&docbDefaultSAXHandler);
Owen Taylor3473f882001-02-23 17:55:21 +00001825}
Daniel Veillardeae522a2001-04-23 13:41:34 +00001826
1827#endif /* LIBXML_DOCB_ENABLED */