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