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