blob: a1079289a8af134ade72f0187bce41e3bdb7949f [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 Veillard62f313b2001-07-04 19:49:14 +0000888 } else if (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) ||
889 ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0))) {
Owen Taylor3473f882001-02-23 17:55:21 +0000890 /*
891 * when validating, the ID registration is done at the attribute
892 * validation level. Otherwise we have to do specific handling here.
893 */
894 if (xmlIsID(ctxt->myDoc, ctxt->node, ret))
895 xmlAddID(&ctxt->vctxt, ctxt->myDoc, value, ret);
896 else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret))
897 xmlAddRef(&ctxt->vctxt, ctxt->myDoc, value, ret);
898 }
899
900 if (nval != NULL)
901 xmlFree(nval);
902 if (name != NULL)
903 xmlFree(name);
904 if (ns != NULL)
905 xmlFree(ns);
906}
907
908/**
909 * startElement:
910 * @ctx: the user data (XML parser context)
911 * @fullname: The element name, including namespace prefix
912 * @atts: An array of name/value attributes pairs, NULL terminated
913 *
914 * called when an opening tag has been processed.
915 */
916void
917startElement(void *ctx, const xmlChar *fullname, const xmlChar **atts)
918{
919 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
920 xmlNodePtr ret;
921 xmlNodePtr parent = ctxt->node;
922 xmlNsPtr ns;
923 xmlChar *name;
924 xmlChar *prefix;
925 const xmlChar *att;
926 const xmlChar *value;
927 int i;
928
929#ifdef DEBUG_SAX
930 xmlGenericError(xmlGenericErrorContext,
931 "SAX.startElement(%s)\n", fullname);
932#endif
933
934 /*
935 * First check on validity:
936 */
937 if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) &&
938 ((ctxt->myDoc->intSubset == NULL) ||
939 ((ctxt->myDoc->intSubset->notations == NULL) &&
940 (ctxt->myDoc->intSubset->elements == NULL) &&
941 (ctxt->myDoc->intSubset->attributes == NULL) &&
942 (ctxt->myDoc->intSubset->entities == NULL)))) {
943 if (ctxt->vctxt.error != NULL) {
944 ctxt->vctxt.error(ctxt->vctxt.userData,
945 "Validation failed: no DTD found !\n");
946 }
947 ctxt->validate = 0;
948 }
949
950
951 /*
952 * Split the full name into a namespace prefix and the tag name
953 */
954 name = xmlSplitQName(ctxt, fullname, &prefix);
955
956
957 /*
958 * Note : the namespace resolution is deferred until the end of the
959 * attributes parsing, since local namespace can be defined as
960 * an attribute at this level.
961 */
962 ret = xmlNewDocNode(ctxt->myDoc, NULL, name, NULL);
963 if (ret == NULL) return;
964 if (ctxt->myDoc->children == NULL) {
965#ifdef DEBUG_SAX_TREE
966 xmlGenericError(xmlGenericErrorContext, "Setting %s as root\n", name);
967#endif
968 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
969 } else if (parent == NULL) {
970 parent = ctxt->myDoc->children;
971 }
972 ctxt->nodemem = -1;
973
974 /*
975 * We are parsing a new node.
976 */
977#ifdef DEBUG_SAX_TREE
978 xmlGenericError(xmlGenericErrorContext, "pushing(%s)\n", name);
979#endif
980 nodePush(ctxt, ret);
981
982 /*
983 * Link the child element
984 */
985 if (parent != NULL) {
986 if (parent->type == XML_ELEMENT_NODE) {
987#ifdef DEBUG_SAX_TREE
988 xmlGenericError(xmlGenericErrorContext,
989 "adding child %s to %s\n", name, parent->name);
990#endif
991 xmlAddChild(parent, ret);
992 } else {
993#ifdef DEBUG_SAX_TREE
994 xmlGenericError(xmlGenericErrorContext,
995 "adding sibling %s to ", name);
996 xmlDebugDumpOneNode(stderr, parent, 0);
997#endif
998 xmlAddSibling(parent, ret);
999 }
1000 }
1001
1002 /*
1003 * process all the attributes whose name start with "xml"
1004 */
1005 if (atts != NULL) {
1006 i = 0;
1007 att = atts[i++];
1008 value = atts[i++];
1009 if (!ctxt->html) {
1010 while ((att != NULL) && (value != NULL)) {
1011 if ((att[0] == 'x') && (att[1] == 'm') && (att[2] == 'l'))
1012 attribute(ctxt, att, value);
1013
1014 att = atts[i++];
1015 value = atts[i++];
1016 }
1017 }
1018 }
1019
1020 /*
1021 * Search the namespace, note that since the attributes have been
1022 * processed, the local namespaces are available.
1023 */
1024 ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
1025 if ((ns == NULL) && (parent != NULL))
1026 ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
1027 if ((prefix != NULL) && (ns == NULL)) {
1028 ns = xmlNewNs(ret, NULL, prefix);
1029 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1030 ctxt->sax->warning(ctxt->userData,
1031 "Namespace prefix %s is not defined\n", prefix);
1032 }
1033 xmlSetNs(ret, ns);
1034
1035 /*
1036 * process all the other attributes
1037 */
1038 if (atts != NULL) {
1039 i = 0;
1040 att = atts[i++];
1041 value = atts[i++];
1042 if (ctxt->html) {
1043 while (att != NULL) {
1044 attribute(ctxt, att, value);
1045 att = atts[i++];
1046 value = atts[i++];
1047 }
1048 } else {
1049 while ((att != NULL) && (value != NULL)) {
1050 if ((att[0] != 'x') || (att[1] != 'm') || (att[2] != 'l'))
1051 attribute(ctxt, att, value);
1052
1053 /*
1054 * Next ones
1055 */
1056 att = atts[i++];
1057 value = atts[i++];
1058 }
1059 }
1060 }
1061
1062 /*
1063 * If it's the Document root, finish the Dtd validation and
1064 * check the document root element for validity
1065 */
1066 if ((ctxt->validate) && (ctxt->vctxt.finishDtd == 0)) {
1067 ctxt->valid &= xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc);
1068 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
1069 ctxt->vctxt.finishDtd = 1;
1070 }
1071
1072 if (prefix != NULL)
1073 xmlFree(prefix);
1074 if (name != NULL)
1075 xmlFree(name);
1076
1077}
1078
1079/**
1080 * endElement:
1081 * @ctx: the user data (XML parser context)
1082 * @name: The element name
1083 *
1084 * called when the end of an element has been detected.
1085 */
1086void
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001087endElement(void *ctx, const xmlChar *name ATTRIBUTE_UNUSED)
Owen Taylor3473f882001-02-23 17:55:21 +00001088{
1089 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1090 xmlParserNodeInfo node_info;
1091 xmlNodePtr cur = ctxt->node;
1092
1093#ifdef DEBUG_SAX
1094 if (name == NULL)
1095 xmlGenericError(xmlGenericErrorContext, "SAX.endElement(NULL)\n");
1096 else
1097 xmlGenericError(xmlGenericErrorContext, "SAX.endElement(%s)\n", name);
1098#endif
1099
1100 /* Capture end position and add node */
1101 if (cur != NULL && ctxt->record_info) {
1102 node_info.end_pos = ctxt->input->cur - ctxt->input->base;
1103 node_info.end_line = ctxt->input->line;
1104 node_info.node = cur;
1105 xmlParserAddNodeInfo(ctxt, &node_info);
1106 }
1107 ctxt->nodemem = -1;
1108
1109 if (ctxt->validate && ctxt->wellFormed &&
1110 ctxt->myDoc && ctxt->myDoc->intSubset)
1111 ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc,
1112 cur);
1113
1114
1115 /*
1116 * end of parsing of this node.
1117 */
1118#ifdef DEBUG_SAX_TREE
1119 xmlGenericError(xmlGenericErrorContext, "popping(%s)\n", cur->name);
1120#endif
1121 nodePop(ctxt);
1122}
1123
1124/**
1125 * reference:
1126 * @ctx: the user data (XML parser context)
1127 * @name: The entity name
1128 *
1129 * called when an entity reference is detected.
1130 */
1131void
1132reference(void *ctx, const xmlChar *name)
1133{
1134 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1135 xmlNodePtr ret;
1136
1137#ifdef DEBUG_SAX
1138 xmlGenericError(xmlGenericErrorContext,
1139 "SAX.reference(%s)\n", name);
1140#endif
1141 if (name[0] == '#')
1142 ret = xmlNewCharRef(ctxt->myDoc, name);
1143 else
1144 ret = xmlNewReference(ctxt->myDoc, name);
1145#ifdef DEBUG_SAX_TREE
1146 xmlGenericError(xmlGenericErrorContext,
1147 "add reference %s to %s \n", name, ctxt->node->name);
1148#endif
1149 xmlAddChild(ctxt->node, ret);
1150}
1151
1152/**
1153 * characters:
1154 * @ctx: the user data (XML parser context)
1155 * @ch: a xmlChar string
1156 * @len: the number of xmlChar
1157 *
1158 * receiving some chars from the parser.
1159 * Question: how much at a time ???
1160 */
1161void
1162characters(void *ctx, const xmlChar *ch, int len)
1163{
1164 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1165 xmlNodePtr lastChild;
1166
1167#ifdef DEBUG_SAX
1168 xmlGenericError(xmlGenericErrorContext,
1169 "SAX.characters(%.30s, %d)\n", ch, len);
1170#endif
1171 /*
1172 * Handle the data if any. If there is no child
1173 * add it as content, otherwise if the last child is text,
1174 * concatenate it, else create a new node of type text.
1175 */
1176
1177 if (ctxt->node == NULL) {
1178#ifdef DEBUG_SAX_TREE
1179 xmlGenericError(xmlGenericErrorContext,
1180 "add chars: ctxt->node == NULL !\n");
1181#endif
1182 return;
1183 }
1184 lastChild = xmlGetLastChild(ctxt->node);
1185#ifdef DEBUG_SAX_TREE
1186 xmlGenericError(xmlGenericErrorContext,
1187 "add chars to %s \n", ctxt->node->name);
1188#endif
1189
1190 /*
1191 * Here we needed an accelerator mechanism in case of very large
1192 * elements. Use an attribute in the structure !!!
1193 */
1194 if (lastChild == NULL) {
1195 /* first node, first time */
1196 xmlNodeAddContentLen(ctxt->node, ch, len);
1197#ifndef XML_USE_BUFFER_CONTENT
1198 if (ctxt->node->children != NULL) {
1199 ctxt->nodelen = len;
1200 ctxt->nodemem = len + 1;
1201 }
1202#endif
1203 } else {
Daniel Veillard80f32572001-03-07 19:45:40 +00001204 int isText = xmlNodeIsText(lastChild);
1205 if ((isText) && (ctxt->nodemem != 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001206#ifndef XML_USE_BUFFER_CONTENT
1207 /*
1208 * The whole point of maintaining nodelen and nodemem,
1209 * xmlTextConcat is too costly, i.e. compute lenght,
1210 * reallocate a new buffer, move data, append ch. Here
1211 * We try to minimaze realloc() uses and avoid copying
1212 * and recomputing lenght over and over.
1213 */
1214 if (ctxt->nodelen + len >= ctxt->nodemem) {
1215 xmlChar *newbuf;
1216 int size;
1217
1218 size = ctxt->nodemem + len;
1219 size *= 2;
1220 newbuf = (xmlChar *) xmlRealloc(lastChild->content,size);
1221 if (newbuf == NULL) {
1222 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1223 ctxt->sax->error(ctxt->userData,
1224 "SAX.characters(): out of memory\n");
1225 return;
1226 }
1227 ctxt->nodemem = size;
1228 lastChild->content = newbuf;
1229 }
1230 memcpy(&lastChild->content[ctxt->nodelen], ch, len);
1231 ctxt->nodelen += len;
1232 lastChild->content[ctxt->nodelen] = 0;
1233#else
1234 xmlTextConcat(lastChild, ch, len);
1235#endif
Daniel Veillard80f32572001-03-07 19:45:40 +00001236 } else if (isText) {
1237 xmlTextConcat(lastChild, ch, len);
1238 if (ctxt->node->children != NULL) {
1239 ctxt->nodelen = xmlStrlen(lastChild->content);
1240 ctxt->nodemem = ctxt->nodelen + 1;
1241 }
Owen Taylor3473f882001-02-23 17:55:21 +00001242 } else {
1243 /* Mixed content, first time */
1244 lastChild = xmlNewTextLen(ch, len);
1245 xmlAddChild(ctxt->node, lastChild);
1246#ifndef XML_USE_BUFFER_CONTENT
1247 if (ctxt->node->children != NULL) {
1248 ctxt->nodelen = len;
1249 ctxt->nodemem = len + 1;
1250 }
1251#endif
1252 }
1253 }
1254}
1255
1256/**
1257 * ignorableWhitespace:
1258 * @ctx: the user data (XML parser context)
1259 * @ch: a xmlChar string
1260 * @len: the number of xmlChar
1261 *
1262 * receiving some ignorable whitespaces from the parser.
1263 * Question: how much at a time ???
1264 */
1265void
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001266ignorableWhitespace(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch ATTRIBUTE_UNUSED, int len ATTRIBUTE_UNUSED)
Owen Taylor3473f882001-02-23 17:55:21 +00001267{
1268 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
1269#ifdef DEBUG_SAX
1270 xmlGenericError(xmlGenericErrorContext,
1271 "SAX.ignorableWhitespace(%.30s, %d)\n", ch, len);
1272#endif
1273}
1274
1275/**
1276 * processingInstruction:
1277 * @ctx: the user data (XML parser context)
1278 * @target: the target name
1279 * @data: the PI data's
1280 *
1281 * A processing instruction has been parsed.
1282 */
1283void
1284processingInstruction(void *ctx, const xmlChar *target,
1285 const xmlChar *data)
1286{
1287 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1288 xmlNodePtr ret;
1289 xmlNodePtr parent = ctxt->node;
1290
1291#ifdef DEBUG_SAX
1292 xmlGenericError(xmlGenericErrorContext,
1293 "SAX.processingInstruction(%s, %s)\n", target, data);
1294#endif
1295
1296 ret = xmlNewPI(target, data);
1297 if (ret == NULL) return;
1298 parent = ctxt->node;
1299
1300 if (ctxt->inSubset == 1) {
1301 xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
1302 return;
1303 } else if (ctxt->inSubset == 2) {
1304 xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
1305 return;
1306 }
1307 if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
1308#ifdef DEBUG_SAX_TREE
1309 xmlGenericError(xmlGenericErrorContext,
1310 "Setting PI %s as root\n", target);
1311#endif
1312 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
1313 return;
1314 }
1315 if (parent->type == XML_ELEMENT_NODE) {
1316#ifdef DEBUG_SAX_TREE
1317 xmlGenericError(xmlGenericErrorContext,
1318 "adding PI %s child to %s\n", target, parent->name);
1319#endif
1320 xmlAddChild(parent, ret);
1321 } else {
1322#ifdef DEBUG_SAX_TREE
1323 xmlGenericError(xmlGenericErrorContext,
1324 "adding PI %s sibling to ", target);
1325 xmlDebugDumpOneNode(stderr, parent, 0);
1326#endif
1327 xmlAddSibling(parent, ret);
1328 }
1329}
1330
1331/**
1332 * globalNamespace:
1333 * @ctx: the user data (XML parser context)
1334 * @href: the namespace associated URN
1335 * @prefix: the namespace prefix
1336 *
1337 * An old global namespace has been parsed.
1338 */
1339void
1340globalNamespace(void *ctx, const xmlChar *href, const xmlChar *prefix)
1341{
1342 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1343#ifdef DEBUG_SAX
1344 xmlGenericError(xmlGenericErrorContext,
1345 "SAX.globalNamespace(%s, %s)\n", href, prefix);
1346#endif
1347 xmlNewGlobalNs(ctxt->myDoc, href, prefix);
1348}
1349
1350/**
1351 * setNamespace:
1352 * @ctx: the user data (XML parser context)
1353 * @name: the namespace prefix
1354 *
1355 * Set the current element namespace.
1356 */
1357
1358void
1359setNamespace(void *ctx, const xmlChar *name)
1360{
1361 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1362 xmlNsPtr ns;
1363 xmlNodePtr parent;
1364
1365#ifdef DEBUG_SAX
1366 xmlGenericError(xmlGenericErrorContext, "SAX.setNamespace(%s)\n", name);
1367#endif
1368 ns = xmlSearchNs(ctxt->myDoc, ctxt->node, name);
1369 if (ns == NULL) { /* ctxt->node may not have a parent yet ! */
1370 if (ctxt->nodeNr >= 2) {
1371 parent = ctxt->nodeTab[ctxt->nodeNr - 2];
1372 if (parent != NULL)
1373 ns = xmlSearchNs(ctxt->myDoc, parent, name);
1374 }
1375 }
1376 xmlSetNs(ctxt->node, ns);
1377}
1378
1379/**
1380 * getNamespace:
1381 * @ctx: the user data (XML parser context)
1382 *
1383 * Get the current element namespace.
1384 *
1385 * Returns the xmlNsPtr or NULL if none
1386 */
1387
1388xmlNsPtr
1389getNamespace(void *ctx)
1390{
1391 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1392 xmlNsPtr ret;
1393
1394#ifdef DEBUG_SAX
1395 xmlGenericError(xmlGenericErrorContext, "SAX.getNamespace()\n");
1396#endif
1397 ret = ctxt->node->ns;
1398 return(ret);
1399}
1400
1401/**
1402 * checkNamespace:
1403 * @ctx: the user data (XML parser context)
1404 * @namespace: the namespace to check against
1405 *
1406 * Check that the current element namespace is the same as the
1407 * one read upon parsing.
1408 *
1409 * Returns 1 if true 0 otherwise
1410 */
1411
1412int
1413checkNamespace(void *ctx, xmlChar *namespace)
1414{
1415 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1416 xmlNodePtr cur = ctxt->node;
1417
1418#ifdef DEBUG_SAX
1419 xmlGenericError(xmlGenericErrorContext,
1420 "SAX.checkNamespace(%s)\n", namespace);
1421#endif
1422
1423 /*
1424 * Check that the Name in the ETag is the same as in the STag.
1425 */
1426 if (namespace == NULL) {
1427 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
1428 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1429 ctxt->sax->error(ctxt,
1430 "End tags for %s don't hold the namespace %s\n",
1431 cur->name, cur->ns->prefix);
1432 ctxt->wellFormed = 0;
1433 }
1434 } else {
1435 if ((cur->ns == NULL) || (cur->ns->prefix == NULL)) {
1436 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1437 ctxt->sax->error(ctxt,
1438 "End tags %s holds a prefix %s not used by the open tag\n",
1439 cur->name, namespace);
1440 ctxt->wellFormed = 0;
1441 } else if (!xmlStrEqual(namespace, cur->ns->prefix)) {
1442 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1443 ctxt->sax->error(ctxt,
1444 "Start and End tags for %s don't use the same namespaces: %s and %s\n",
1445 cur->name, cur->ns->prefix, namespace);
1446 ctxt->wellFormed = 0;
1447 } else
1448 return(1);
1449 }
1450 return(0);
1451}
1452
1453/**
1454 * namespaceDecl:
1455 * @ctx: the user data (XML parser context)
1456 * @href: the namespace associated URN
1457 * @prefix: the namespace prefix
1458 *
1459 * A namespace has been parsed.
1460 */
1461void
1462namespaceDecl(void *ctx, const xmlChar *href, const xmlChar *prefix)
1463{
1464 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1465#ifdef DEBUG_SAX
1466 if (prefix == NULL)
1467 xmlGenericError(xmlGenericErrorContext,
1468 "SAX.namespaceDecl(%s, NULL)\n", href);
1469 else
1470 xmlGenericError(xmlGenericErrorContext,
1471 "SAX.namespaceDecl(%s, %s)\n", href, prefix);
1472#endif
1473 xmlNewNs(ctxt->node, href, prefix);
1474}
1475
1476/**
1477 * comment:
1478 * @ctx: the user data (XML parser context)
1479 * @value: the comment content
1480 *
1481 * A comment has been parsed.
1482 */
1483void
1484comment(void *ctx, const xmlChar *value)
1485{
1486 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1487 xmlNodePtr ret;
1488 xmlNodePtr parent = ctxt->node;
1489
1490#ifdef DEBUG_SAX
1491 xmlGenericError(xmlGenericErrorContext, "SAX.comment(%s)\n", value);
1492#endif
1493 ret = xmlNewDocComment(ctxt->myDoc, value);
1494 if (ret == NULL) return;
1495
1496 if (ctxt->inSubset == 1) {
1497 xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
1498 return;
1499 } else if (ctxt->inSubset == 2) {
1500 xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
1501 return;
1502 }
1503 if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
1504#ifdef DEBUG_SAX_TREE
1505 xmlGenericError(xmlGenericErrorContext,
1506 "Setting comment as root\n");
1507#endif
1508 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
1509 return;
1510 }
1511 if (parent->type == XML_ELEMENT_NODE) {
1512#ifdef DEBUG_SAX_TREE
1513 xmlGenericError(xmlGenericErrorContext,
1514 "adding comment child to %s\n", parent->name);
1515#endif
1516 xmlAddChild(parent, ret);
1517 } else {
1518#ifdef DEBUG_SAX_TREE
1519 xmlGenericError(xmlGenericErrorContext,
1520 "adding comment sibling to ");
1521 xmlDebugDumpOneNode(stderr, parent, 0);
1522#endif
1523 xmlAddSibling(parent, ret);
1524 }
1525}
1526
1527/**
1528 * cdataBlock:
1529 * @ctx: the user data (XML parser context)
1530 * @value: The pcdata content
1531 * @len: the block length
1532 *
1533 * called when a pcdata block has been parsed
1534 */
1535void
1536cdataBlock(void *ctx, const xmlChar *value, int len)
1537{
1538 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1539 xmlNodePtr ret, lastChild;
1540
1541#ifdef DEBUG_SAX
1542 xmlGenericError(xmlGenericErrorContext,
1543 "SAX.pcdata(%.10s, %d)\n", value, len);
1544#endif
1545 lastChild = xmlGetLastChild(ctxt->node);
1546#ifdef DEBUG_SAX_TREE
1547 xmlGenericError(xmlGenericErrorContext,
1548 "add chars to %s \n", ctxt->node->name);
1549#endif
1550 if ((lastChild != NULL) &&
1551 (lastChild->type == XML_CDATA_SECTION_NODE)) {
1552 xmlTextConcat(lastChild, value, len);
1553 } else {
1554 ret = xmlNewCDataBlock(ctxt->myDoc, value, len);
1555 xmlAddChild(ctxt->node, ret);
1556 }
1557}
1558
1559/*
1560 * Default handler for XML, builds the DOM tree
1561 */
1562xmlSAXHandler xmlDefaultSAXHandler = {
1563 internalSubset,
1564 isStandalone,
1565 hasInternalSubset,
1566 hasExternalSubset,
1567 resolveEntity,
1568 getEntity,
1569 entityDecl,
1570 notationDecl,
1571 attributeDecl,
1572 elementDecl,
1573 unparsedEntityDecl,
1574 setDocumentLocator,
1575 startDocument,
1576 endDocument,
1577 startElement,
1578 endElement,
1579 reference,
1580 characters,
1581 ignorableWhitespace,
1582 processingInstruction,
1583 comment,
1584 xmlParserWarning,
1585 xmlParserError,
1586 xmlParserError,
1587 getParameterEntity,
1588 cdataBlock,
1589 externalSubset,
1590};
1591
1592/**
1593 * xmlDefaultSAXHandlerInit:
1594 *
1595 * Initialize the default SAX handler
1596 */
1597void
1598xmlDefaultSAXHandlerInit(void)
1599{
1600 xmlDefaultSAXHandler.internalSubset = internalSubset;
1601 xmlDefaultSAXHandler.externalSubset = externalSubset;
1602 xmlDefaultSAXHandler.isStandalone = isStandalone;
1603 xmlDefaultSAXHandler.hasInternalSubset = hasInternalSubset;
1604 xmlDefaultSAXHandler.hasExternalSubset = hasExternalSubset;
1605 xmlDefaultSAXHandler.resolveEntity = resolveEntity;
1606 xmlDefaultSAXHandler.getEntity = getEntity;
1607 xmlDefaultSAXHandler.getParameterEntity = getParameterEntity;
1608 xmlDefaultSAXHandler.entityDecl = entityDecl;
1609 xmlDefaultSAXHandler.attributeDecl = attributeDecl;
1610 xmlDefaultSAXHandler.elementDecl = elementDecl;
1611 xmlDefaultSAXHandler.notationDecl = notationDecl;
1612 xmlDefaultSAXHandler.unparsedEntityDecl = unparsedEntityDecl;
1613 xmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
1614 xmlDefaultSAXHandler.startDocument = startDocument;
1615 xmlDefaultSAXHandler.endDocument = endDocument;
1616 xmlDefaultSAXHandler.startElement = startElement;
1617 xmlDefaultSAXHandler.endElement = endElement;
1618 xmlDefaultSAXHandler.reference = reference;
1619 xmlDefaultSAXHandler.characters = characters;
1620 xmlDefaultSAXHandler.cdataBlock = cdataBlock;
1621 xmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
1622 xmlDefaultSAXHandler.processingInstruction = processingInstruction;
1623 xmlDefaultSAXHandler.comment = comment;
1624 if (xmlGetWarningsDefaultValue == 0)
1625 xmlDefaultSAXHandler.warning = NULL;
1626 else
1627 xmlDefaultSAXHandler.warning = xmlParserWarning;
1628 xmlDefaultSAXHandler.error = xmlParserError;
1629 xmlDefaultSAXHandler.fatalError = xmlParserError;
1630}
1631
Daniel Veillardeae522a2001-04-23 13:41:34 +00001632#ifdef LIBXML_HTML_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001633/*
1634 * Default handler for HTML, builds the DOM tree
1635 */
1636xmlSAXHandler htmlDefaultSAXHandler = {
1637 internalSubset,
1638 NULL,
1639 NULL,
1640 NULL,
1641 NULL,
1642 getEntity,
1643 NULL,
1644 NULL,
1645 NULL,
1646 NULL,
1647 NULL,
1648 setDocumentLocator,
1649 startDocument,
1650 endDocument,
1651 startElement,
1652 endElement,
1653 NULL,
1654 characters,
1655 ignorableWhitespace,
1656 NULL,
1657 comment,
1658 xmlParserWarning,
1659 xmlParserError,
1660 xmlParserError,
1661 getParameterEntity,
1662 cdataBlock,
1663 NULL,
1664};
1665
1666/**
1667 * htmlDefaultSAXHandlerInit:
1668 *
1669 * Initialize the default SAX handler
1670 */
1671void
1672htmlDefaultSAXHandlerInit(void)
1673{
1674 htmlDefaultSAXHandler.internalSubset = internalSubset;
1675 htmlDefaultSAXHandler.externalSubset = NULL;
1676 htmlDefaultSAXHandler.isStandalone = NULL;
1677 htmlDefaultSAXHandler.hasInternalSubset = NULL;
1678 htmlDefaultSAXHandler.hasExternalSubset = NULL;
1679 htmlDefaultSAXHandler.resolveEntity = NULL;
1680 htmlDefaultSAXHandler.getEntity = getEntity;
1681 htmlDefaultSAXHandler.getParameterEntity = NULL;
1682 htmlDefaultSAXHandler.entityDecl = NULL;
1683 htmlDefaultSAXHandler.attributeDecl = NULL;
1684 htmlDefaultSAXHandler.elementDecl = NULL;
1685 htmlDefaultSAXHandler.notationDecl = NULL;
1686 htmlDefaultSAXHandler.unparsedEntityDecl = NULL;
1687 htmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
1688 htmlDefaultSAXHandler.startDocument = startDocument;
1689 htmlDefaultSAXHandler.endDocument = endDocument;
1690 htmlDefaultSAXHandler.startElement = startElement;
1691 htmlDefaultSAXHandler.endElement = endElement;
1692 htmlDefaultSAXHandler.reference = NULL;
1693 htmlDefaultSAXHandler.characters = characters;
1694 htmlDefaultSAXHandler.cdataBlock = cdataBlock;
1695 htmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
1696 htmlDefaultSAXHandler.processingInstruction = NULL;
1697 htmlDefaultSAXHandler.comment = comment;
1698 htmlDefaultSAXHandler.warning = xmlParserWarning;
1699 htmlDefaultSAXHandler.error = xmlParserError;
1700 htmlDefaultSAXHandler.fatalError = xmlParserError;
1701}
Daniel Veillardeae522a2001-04-23 13:41:34 +00001702#endif /* LIBXML_HTML_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001703
Daniel Veillardeae522a2001-04-23 13:41:34 +00001704#ifdef LIBXML_DOCB_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001705/*
Daniel Veillardeae522a2001-04-23 13:41:34 +00001706 * Default handler for SGML DocBook, builds the DOM tree
Owen Taylor3473f882001-02-23 17:55:21 +00001707 */
Daniel Veillardeae522a2001-04-23 13:41:34 +00001708xmlSAXHandler docbDefaultSAXHandler = {
Owen Taylor3473f882001-02-23 17:55:21 +00001709 internalSubset,
Daniel Veillard61b33d52001-04-24 13:55:12 +00001710 isStandalone,
1711 hasInternalSubset,
1712 hasExternalSubset,
1713 resolveEntity,
Owen Taylor3473f882001-02-23 17:55:21 +00001714 getEntity,
Daniel Veillard61b33d52001-04-24 13:55:12 +00001715 entityDecl,
Owen Taylor3473f882001-02-23 17:55:21 +00001716 NULL,
1717 NULL,
1718 NULL,
1719 NULL,
1720 setDocumentLocator,
1721 startDocument,
1722 endDocument,
1723 startElement,
1724 endElement,
Daniel Veillard1034da22001-04-25 19:06:28 +00001725 reference,
Owen Taylor3473f882001-02-23 17:55:21 +00001726 characters,
1727 ignorableWhitespace,
1728 NULL,
1729 comment,
1730 xmlParserWarning,
1731 xmlParserError,
1732 xmlParserError,
1733 getParameterEntity,
1734 NULL,
1735 NULL,
1736};
1737
1738/**
Daniel Veillardeae522a2001-04-23 13:41:34 +00001739 * docbDefaultSAXHandlerInit:
Owen Taylor3473f882001-02-23 17:55:21 +00001740 *
1741 * Initialize the default SAX handler
1742 */
1743void
Daniel Veillardeae522a2001-04-23 13:41:34 +00001744docbDefaultSAXHandlerInit(void)
Owen Taylor3473f882001-02-23 17:55:21 +00001745{
Daniel Veillardeae522a2001-04-23 13:41:34 +00001746 docbDefaultSAXHandler.internalSubset = internalSubset;
1747 docbDefaultSAXHandler.externalSubset = NULL;
Daniel Veillard61b33d52001-04-24 13:55:12 +00001748 docbDefaultSAXHandler.isStandalone = isStandalone;
1749 docbDefaultSAXHandler.hasInternalSubset = hasInternalSubset;
1750 docbDefaultSAXHandler.hasExternalSubset = hasExternalSubset;
1751 docbDefaultSAXHandler.resolveEntity = resolveEntity;
Daniel Veillardeae522a2001-04-23 13:41:34 +00001752 docbDefaultSAXHandler.getEntity = getEntity;
1753 docbDefaultSAXHandler.getParameterEntity = NULL;
Daniel Veillard61b33d52001-04-24 13:55:12 +00001754 docbDefaultSAXHandler.entityDecl = entityDecl;
Daniel Veillardeae522a2001-04-23 13:41:34 +00001755 docbDefaultSAXHandler.attributeDecl = NULL;
1756 docbDefaultSAXHandler.elementDecl = NULL;
1757 docbDefaultSAXHandler.notationDecl = NULL;
1758 docbDefaultSAXHandler.unparsedEntityDecl = NULL;
1759 docbDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
1760 docbDefaultSAXHandler.startDocument = startDocument;
1761 docbDefaultSAXHandler.endDocument = endDocument;
1762 docbDefaultSAXHandler.startElement = startElement;
1763 docbDefaultSAXHandler.endElement = endElement;
Daniel Veillard1034da22001-04-25 19:06:28 +00001764 docbDefaultSAXHandler.reference = reference;
Daniel Veillardeae522a2001-04-23 13:41:34 +00001765 docbDefaultSAXHandler.characters = characters;
1766 docbDefaultSAXHandler.cdataBlock = NULL;
1767 docbDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
1768 docbDefaultSAXHandler.processingInstruction = NULL;
1769 docbDefaultSAXHandler.comment = comment;
1770 docbDefaultSAXHandler.warning = xmlParserWarning;
1771 docbDefaultSAXHandler.error = xmlParserError;
1772 docbDefaultSAXHandler.fatalError = xmlParserError;
Owen Taylor3473f882001-02-23 17:55:21 +00001773}
Daniel Veillardeae522a2001-04-23 13:41:34 +00001774
1775#endif /* LIBXML_DOCB_ENABLED */