blob: 6789f43305cf821a4e937b2777fdb7207752eac8 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * SAX.c : Default SAX handler to build a tree.
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00006 * Daniel Veillard <daniel@veillard.com>
Owen Taylor3473f882001-02-23 17:55:21 +00007 */
8
9
Bjorn Reese70a9da52001-04-21 16:57:29 +000010#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000011#include <stdlib.h>
12#include <string.h>
13#include <libxml/xmlmemory.h>
14#include <libxml/tree.h>
15#include <libxml/parser.h>
16#include <libxml/parserInternals.h>
17#include <libxml/valid.h>
18#include <libxml/entities.h>
19#include <libxml/xmlerror.h>
20#include <libxml/debugXML.h>
21#include <libxml/xmlIO.h>
22#include <libxml/SAX.h>
23#include <libxml/uri.h>
24#include <libxml/HTMLtree.h>
25
26/* #define DEBUG_SAX */
27/* #define DEBUG_SAX_TREE */
28
29/**
30 * getPublicId:
31 * @ctx: the user data (XML parser context)
32 *
33 * Return the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
34 *
35 * Returns a xmlChar *
36 */
37const xmlChar *
Daniel Veillardc86a4fa2001-03-26 16:28:29 +000038getPublicId(void *ctx ATTRIBUTE_UNUSED)
Owen Taylor3473f882001-02-23 17:55:21 +000039{
40 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
41 return(NULL);
42}
43
44/**
45 * getSystemId:
46 * @ctx: the user data (XML parser context)
47 *
48 * Return the system ID, basically URL or filename e.g.
49 * http://www.sgmlsource.com/dtds/memo.dtd
50 *
51 * Returns a xmlChar *
52 */
53const xmlChar *
54getSystemId(void *ctx)
55{
56 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard56a4cb82001-03-24 17:00:36 +000057 return((const xmlChar *) ctxt->input->filename);
Owen Taylor3473f882001-02-23 17:55:21 +000058}
59
60/**
61 * getLineNumber:
62 * @ctx: the user data (XML parser context)
63 *
64 * Return the line number of the current parsing point.
65 *
66 * Returns an int
67 */
68int
69getLineNumber(void *ctx)
70{
71 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
72 return(ctxt->input->line);
73}
74
75/**
76 * getColumnNumber:
77 * @ctx: the user data (XML parser context)
78 *
79 * Return the column number of the current parsing point.
80 *
81 * Returns an int
82 */
83int
84getColumnNumber(void *ctx)
85{
86 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
87 return(ctxt->input->col);
88}
89
90/*
91 * The default SAX Locator.
92 */
93
94xmlSAXLocator xmlDefaultSAXLocator = {
95 getPublicId, getSystemId, getLineNumber, getColumnNumber
96};
97
98/**
99 * isStandalone:
100 * @ctx: the user data (XML parser context)
101 *
102 * Is this document tagged standalone ?
103 *
104 * Returns 1 if true
105 */
106int
107isStandalone(void *ctx)
108{
109 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
110 return(ctxt->myDoc->standalone == 1);
111}
112
113/**
114 * hasInternalSubset:
115 * @ctx: the user data (XML parser context)
116 *
117 * Does this document has an internal subset
118 *
119 * Returns 1 if true
120 */
121int
122hasInternalSubset(void *ctx)
123{
124 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
125 return(ctxt->myDoc->intSubset != NULL);
126}
127
128/**
129 * hasExternalSubset:
130 * @ctx: the user data (XML parser context)
131 *
132 * Does this document has an external subset
133 *
134 * Returns 1 if true
135 */
136int
137hasExternalSubset(void *ctx)
138{
139 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
140 return(ctxt->myDoc->extSubset != NULL);
141}
142
143/**
144 * internalSubset:
145 * @ctx: the user data (XML parser context)
146 * @name: the root element name
147 * @ExternalID: the external ID
148 * @SystemID: the SYSTEM ID (e.g. filename or URL)
149 *
150 * Callback on internal subset declaration.
151 */
152void
153internalSubset(void *ctx, const xmlChar *name,
154 const xmlChar *ExternalID, const xmlChar *SystemID)
155{
156 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
157 xmlDtdPtr dtd;
158#ifdef DEBUG_SAX
159 xmlGenericError(xmlGenericErrorContext,
160 "SAX.internalSubset(%s, %s, %s)\n",
161 name, ExternalID, SystemID);
162#endif
163
164 if (ctxt->myDoc == NULL)
165 return;
166 dtd = xmlGetIntSubset(ctxt->myDoc);
167 if (dtd != NULL) {
168 if (ctxt->html)
169 return;
170 xmlUnlinkNode((xmlNodePtr) dtd);
171 xmlFreeDtd(dtd);
172 ctxt->myDoc->intSubset = NULL;
173 }
174 ctxt->myDoc->intSubset =
175 xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
176}
177
178/**
179 * externalSubset:
180 * @ctx: the user data (XML parser context)
181 * @name: the root element name
182 * @ExternalID: the external ID
183 * @SystemID: the SYSTEM ID (e.g. filename or URL)
184 *
185 * Callback on external subset declaration.
186 */
187void
188externalSubset(void *ctx, const xmlChar *name,
189 const xmlChar *ExternalID, const xmlChar *SystemID)
190{
191 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
192#ifdef DEBUG_SAX
193 xmlGenericError(xmlGenericErrorContext,
194 "SAX.externalSubset(%s, %s, %s)\n",
195 name, ExternalID, SystemID);
196#endif
197 if (((ExternalID != NULL) || (SystemID != NULL)) &&
Daniel Veillard9403a042001-05-28 11:00:53 +0000198 (((ctxt->validate) || (ctxt->loadsubset != 0)) &&
Owen Taylor3473f882001-02-23 17:55:21 +0000199 (ctxt->wellFormed && ctxt->myDoc))) {
200 /*
201 * Try to fetch and parse the external subset.
202 */
203 xmlParserInputPtr oldinput;
204 int oldinputNr;
205 int oldinputMax;
206 xmlParserInputPtr *oldinputTab;
207 int oldwellFormed;
208 xmlParserInputPtr input = NULL;
209 xmlCharEncoding enc;
210 int oldcharset;
211
212 /*
213 * Ask the Entity resolver to load the damn thing
214 */
215 if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
216 input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID,
217 SystemID);
218 if (input == NULL) {
219 return;
220 }
221
222 xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID);
223
224 /*
225 * make sure we won't destroy the main document context
226 */
227 oldinput = ctxt->input;
228 oldinputNr = ctxt->inputNr;
229 oldinputMax = ctxt->inputMax;
230 oldinputTab = ctxt->inputTab;
231 oldwellFormed = ctxt->wellFormed;
232 oldcharset = ctxt->charset;
233
234 ctxt->inputTab = (xmlParserInputPtr *)
235 xmlMalloc(5 * sizeof(xmlParserInputPtr));
236 if (ctxt->inputTab == NULL) {
237 ctxt->errNo = XML_ERR_NO_MEMORY;
238 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
239 ctxt->sax->error(ctxt->userData,
240 "externalSubset: out of memory\n");
241 ctxt->errNo = XML_ERR_NO_MEMORY;
242 ctxt->input = oldinput;
243 ctxt->inputNr = oldinputNr;
244 ctxt->inputMax = oldinputMax;
245 ctxt->inputTab = oldinputTab;
246 ctxt->charset = oldcharset;
247 return;
248 }
249 ctxt->inputNr = 0;
250 ctxt->inputMax = 5;
251 ctxt->input = NULL;
252 xmlPushInput(ctxt, input);
253
254 /*
255 * On the fly encoding conversion if needed
256 */
257 enc = xmlDetectCharEncoding(ctxt->input->cur, 4);
258 xmlSwitchEncoding(ctxt, enc);
259
260 if (input->filename == NULL)
261 input->filename = (char *) xmlStrdup(SystemID);
262 input->line = 1;
263 input->col = 1;
264 input->base = ctxt->input->cur;
265 input->cur = ctxt->input->cur;
266 input->free = NULL;
267
268 /*
269 * let's parse that entity knowing it's an external subset.
270 */
271 xmlParseExternalSubset(ctxt, ExternalID, SystemID);
272
273 /*
274 * Free up the external entities
275 */
276
277 while (ctxt->inputNr > 1)
278 xmlPopInput(ctxt);
279 xmlFreeInputStream(ctxt->input);
280 xmlFree(ctxt->inputTab);
281
282 /*
283 * Restore the parsing context of the main entity
284 */
285 ctxt->input = oldinput;
286 ctxt->inputNr = oldinputNr;
287 ctxt->inputMax = oldinputMax;
288 ctxt->inputTab = oldinputTab;
289 ctxt->charset = oldcharset;
290 /* ctxt->wellFormed = oldwellFormed; */
291 }
292}
293
294/**
295 * resolveEntity:
296 * @ctx: the user data (XML parser context)
297 * @publicId: The public ID of the entity
298 * @systemId: The system ID of the entity
299 *
300 * The entity loader, to control the loading of external entities,
301 * the application can either:
302 * - override this resolveEntity() callback in the SAX block
303 * - or better use the xmlSetExternalEntityLoader() function to
304 * set up it's own entity resolution routine
305 *
306 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
307 */
308xmlParserInputPtr
309resolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
310{
311 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
312 xmlParserInputPtr ret;
313 xmlChar *URI;
314 const char *base = NULL;
315
316 if (ctxt->input != NULL)
317 base = ctxt->input->filename;
318 if (base == NULL)
319 base = ctxt->directory;
320
321 URI = xmlBuildURI(systemId, (const xmlChar *) base);
322
323#ifdef DEBUG_SAX
324 xmlGenericError(xmlGenericErrorContext,
325 "SAX.resolveEntity(%s, %s)\n", publicId, systemId);
326#endif
327
328 ret = xmlLoadExternalEntity((const char *) URI,
329 (const char *) publicId, ctxt);
330 if (URI != NULL)
331 xmlFree(URI);
332 return(ret);
333}
334
335/**
336 * getEntity:
337 * @ctx: the user data (XML parser context)
338 * @name: The entity name
339 *
340 * Get an entity by name
341 *
342 * Returns the xmlEntityPtr if found.
343 */
344xmlEntityPtr
345getEntity(void *ctx, const xmlChar *name)
346{
347 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
348 xmlEntityPtr ret;
349
350#ifdef DEBUG_SAX
351 xmlGenericError(xmlGenericErrorContext,
352 "SAX.getEntity(%s)\n", name);
353#endif
354
355 ret = xmlGetDocEntity(ctxt->myDoc, name);
356 if ((ret != NULL) && (ctxt->validate) && (ret->children == NULL) &&
357 (ret->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
358 /*
359 * for validation purposes we really need to fetch and
360 * parse the external entity
361 */
362 int parse;
363 xmlNodePtr children;
364
365 parse = xmlParseCtxtExternalEntity(ctxt,
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000366 ret->URI, ret->ExternalID, &children);
Owen Taylor3473f882001-02-23 17:55:21 +0000367 xmlAddChildList((xmlNodePtr) ret, children);
368 }
369 return(ret);
370}
371
372/**
373 * getParameterEntity:
374 * @ctx: the user data (XML parser context)
375 * @name: The entity name
376 *
377 * Get a parameter entity by name
378 *
379 * Returns the xmlEntityPtr if found.
380 */
381xmlEntityPtr
382getParameterEntity(void *ctx, const xmlChar *name)
383{
384 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
385 xmlEntityPtr ret;
386
387#ifdef DEBUG_SAX
388 xmlGenericError(xmlGenericErrorContext,
389 "SAX.getParameterEntity(%s)\n", name);
390#endif
391
392 ret = xmlGetParameterEntity(ctxt->myDoc, name);
393 return(ret);
394}
395
396
397/**
398 * entityDecl:
399 * @ctx: the user data (XML parser context)
400 * @name: the entity name
401 * @type: the entity type
402 * @publicId: The public ID of the entity
403 * @systemId: The system ID of the entity
404 * @content: the entity value (without processing).
405 *
406 * An entity definition has been parsed
407 */
408void
409entityDecl(void *ctx, const xmlChar *name, int type,
410 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
411{
412 xmlEntityPtr ent;
413 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
414
415#ifdef DEBUG_SAX
416 xmlGenericError(xmlGenericErrorContext,
417 "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
418 name, type, publicId, systemId, content);
419#endif
420 if (ctxt->inSubset == 1) {
421 ent = xmlAddDocEntity(ctxt->myDoc, name, type, publicId,
422 systemId, content);
423 if ((ent == NULL) && (ctxt->pedantic) &&
424 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
425 ctxt->sax->warning(ctxt,
426 "Entity(%s) already defined in the internal subset\n", name);
427 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
428 xmlChar *URI;
429 const char *base = NULL;
430
431 if (ctxt->input != NULL)
432 base = ctxt->input->filename;
433 if (base == NULL)
434 base = ctxt->directory;
435
436 URI = xmlBuildURI(systemId, (const xmlChar *) base);
437 ent->URI = URI;
438 }
439 } else if (ctxt->inSubset == 2) {
440 ent = xmlAddDtdEntity(ctxt->myDoc, name, type, publicId,
441 systemId, content);
442 if ((ent == NULL) && (ctxt->pedantic) &&
443 (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
444 ctxt->sax->warning(ctxt,
445 "Entity(%s) already defined in the external subset\n", name);
446 if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
447 xmlChar *URI;
448 const char *base = NULL;
449
450 if (ctxt->input != NULL)
451 base = ctxt->input->filename;
452 if (base == NULL)
453 base = ctxt->directory;
454
455 URI = xmlBuildURI(systemId, (const xmlChar *) base);
456 ent->URI = URI;
457 }
458 } else {
459 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
460 ctxt->sax->error(ctxt,
461 "SAX.entityDecl(%s) called while not in subset\n", name);
462 }
463}
464
465/**
466 * attributeDecl:
467 * @ctx: the user data (XML parser context)
468 * @elem: the name of the element
469 * @fullname: the attribute name
470 * @type: the attribute type
471 * @def: the type of default value
472 * @defaultValue: the attribute default value
473 * @tree: the tree of enumerated value set
474 *
475 * An attribute definition has been parsed
476 */
477void
478attributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname,
479 int type, int def, const xmlChar *defaultValue,
480 xmlEnumerationPtr tree)
481{
482 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
483 xmlAttributePtr attr;
484 xmlChar *name = NULL, *prefix = NULL;
485
486#ifdef DEBUG_SAX
487 xmlGenericError(xmlGenericErrorContext,
488 "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
489 elem, fullname, type, def, defaultValue);
490#endif
491 name = xmlSplitQName(ctxt, fullname, &prefix);
492 if (ctxt->inSubset == 1)
493 attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
494 name, prefix, (xmlAttributeType) type,
495 (xmlAttributeDefault) def, defaultValue, tree);
496 else if (ctxt->inSubset == 2)
497 attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, elem,
498 name, prefix, (xmlAttributeType) type,
499 (xmlAttributeDefault) def, defaultValue, tree);
500 else {
501 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
502 ctxt->sax->error(ctxt,
503 "SAX.attributeDecl(%s) called while not in subset\n", name);
504 return;
505 }
506 if (attr == 0) ctxt->valid = 0;
507 if (ctxt->validate && ctxt->wellFormed &&
508 ctxt->myDoc && ctxt->myDoc->intSubset)
509 ctxt->valid &= xmlValidateAttributeDecl(&ctxt->vctxt, ctxt->myDoc,
510 attr);
511 if (prefix != NULL)
512 xmlFree(prefix);
513 if (name != NULL)
514 xmlFree(name);
515}
516
517/**
518 * elementDecl:
519 * @ctx: the user data (XML parser context)
520 * @name: the element name
521 * @type: the element type
522 * @content: the element value tree
523 *
524 * An element definition has been parsed
525 */
526void
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000527elementDecl(void *ctx, const xmlChar * name, int type,
528 xmlElementContentPtr content)
Owen Taylor3473f882001-02-23 17:55:21 +0000529{
530 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
531 xmlElementPtr elem = NULL;
532
533#ifdef DEBUG_SAX
534 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000535 "SAX.elementDecl(%s, %d, ...)\n", name, type);
Owen Taylor3473f882001-02-23 17:55:21 +0000536#endif
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000537
Owen Taylor3473f882001-02-23 17:55:21 +0000538 if (ctxt->inSubset == 1)
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000539 elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset,
540 name, (xmlElementTypeVal) type, content);
Owen Taylor3473f882001-02-23 17:55:21 +0000541 else if (ctxt->inSubset == 2)
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000542 elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->extSubset,
543 name, (xmlElementTypeVal) type, content);
Owen Taylor3473f882001-02-23 17:55:21 +0000544 else {
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000545 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
546 ctxt->sax->error(ctxt,
547 "SAX.elementDecl(%s) called while not in subset\n",
548 name);
549 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000550 }
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000551 if (elem == NULL)
552 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000553 if (ctxt->validate && ctxt->wellFormed &&
554 ctxt->myDoc && ctxt->myDoc->intSubset)
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000555 ctxt->valid &=
556 xmlValidateElementDecl(&ctxt->vctxt, ctxt->myDoc, elem);
Owen Taylor3473f882001-02-23 17:55:21 +0000557}
558
559/**
560 * notationDecl:
561 * @ctx: the user data (XML parser context)
562 * @name: The name of the notation
563 * @publicId: The public ID of the entity
564 * @systemId: The system ID of the entity
565 *
566 * What to do when a notation declaration has been parsed.
567 */
568void
569notationDecl(void *ctx, const xmlChar *name,
570 const xmlChar *publicId, const xmlChar *systemId)
571{
572 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
573 xmlNotationPtr nota = NULL;
574
575#ifdef DEBUG_SAX
576 xmlGenericError(xmlGenericErrorContext,
577 "SAX.notationDecl(%s, %s, %s)\n", name, publicId, systemId);
578#endif
579
580 if (ctxt->inSubset == 1)
581 nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
582 publicId, systemId);
583 else if (ctxt->inSubset == 2)
Daniel Veillard25239c12001-03-14 13:56:48 +0000584 nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, name,
Owen Taylor3473f882001-02-23 17:55:21 +0000585 publicId, systemId);
586 else {
587 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
588 ctxt->sax->error(ctxt,
589 "SAX.notationDecl(%s) called while not in subset\n", name);
590 return;
591 }
592 if (nota == NULL) ctxt->valid = 0;
593 if (ctxt->validate && ctxt->wellFormed &&
594 ctxt->myDoc && ctxt->myDoc->intSubset)
595 ctxt->valid &= xmlValidateNotationDecl(&ctxt->vctxt, ctxt->myDoc,
596 nota);
597}
598
599/**
600 * unparsedEntityDecl:
601 * @ctx: the user data (XML parser context)
602 * @name: The name of the entity
603 * @publicId: The public ID of the entity
604 * @systemId: The system ID of the entity
605 * @notationName: the name of the notation
606 *
607 * What to do when an unparsed entity declaration is parsed
608 */
609void
610unparsedEntityDecl(void *ctx, const xmlChar *name,
611 const xmlChar *publicId, const xmlChar *systemId,
612 const xmlChar *notationName)
613{
614 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
615#ifdef DEBUG_SAX
616 xmlGenericError(xmlGenericErrorContext,
617 "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
618 name, publicId, systemId, notationName);
619#endif
620 if (ctxt->validate && ctxt->wellFormed &&
Daniel Veillarde020c3a2001-03-21 18:06:15 +0000621 ctxt->myDoc && ctxt->myDoc->extSubset)
Owen Taylor3473f882001-02-23 17:55:21 +0000622 ctxt->valid &= xmlValidateNotationUse(&ctxt->vctxt, ctxt->myDoc,
623 notationName);
Daniel Veillarde020c3a2001-03-21 18:06:15 +0000624 if (ctxt->inSubset == 1)
625 xmlAddDocEntity(ctxt->myDoc, name,
626 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
627 publicId, systemId, notationName);
628 else if (ctxt->inSubset == 2)
629 xmlAddDtdEntity(ctxt->myDoc, name,
630 XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
631 publicId, systemId, notationName);
632 else {
633 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
634 ctxt->sax->error(ctxt,
635 "SAX.unparsedEntityDecl(%s) called while not in subset\n", name);
636 }
Owen Taylor3473f882001-02-23 17:55:21 +0000637}
638
639/**
640 * setDocumentLocator:
641 * @ctx: the user data (XML parser context)
642 * @loc: A SAX Locator
643 *
644 * Receive the document locator at startup, actually xmlDefaultSAXLocator
645 * Everything is available on the context, so this is useless in our case.
646 */
647void
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000648setDocumentLocator(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
Owen Taylor3473f882001-02-23 17:55:21 +0000649{
650 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
651#ifdef DEBUG_SAX
652 xmlGenericError(xmlGenericErrorContext,
653 "SAX.setDocumentLocator()\n");
654#endif
655}
656
657/**
658 * startDocument:
659 * @ctx: the user data (XML parser context)
660 *
661 * called when the document start being processed.
662 */
663void
664startDocument(void *ctx)
665{
666 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
667 xmlDocPtr doc;
668
669#ifdef DEBUG_SAX
670 xmlGenericError(xmlGenericErrorContext,
671 "SAX.startDocument()\n");
672#endif
673 if (ctxt->html) {
674 if (ctxt->myDoc == NULL)
675#ifdef LIBXML_HTML_ENABLED
676 ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL);
677#else
678 xmlGenericError(xmlGenericErrorContext,
679 "libxml2 built without HTML support\n");
680#endif
681 } else {
682 doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
683 if (doc != NULL) {
684 if (ctxt->encoding != NULL)
685 doc->encoding = xmlStrdup(ctxt->encoding);
686 else
687 doc->encoding = NULL;
688 doc->standalone = ctxt->standalone;
689 }
690 }
691 if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
692 (ctxt->input != NULL) && (ctxt->input->filename != NULL)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000693 ctxt->myDoc->URL = xmlStrdup((const xmlChar *) ctxt->input->filename);
Owen Taylor3473f882001-02-23 17:55:21 +0000694 }
695}
696
697/**
698 * endDocument:
699 * @ctx: the user data (XML parser context)
700 *
701 * called when the document end has been detected.
702 */
703void
704endDocument(void *ctx)
705{
706 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
707#ifdef DEBUG_SAX
708 xmlGenericError(xmlGenericErrorContext,
709 "SAX.endDocument()\n");
710#endif
711 if (ctxt->validate && ctxt->wellFormed &&
712 ctxt->myDoc && ctxt->myDoc->intSubset)
713 ctxt->valid &= xmlValidateDocumentFinal(&ctxt->vctxt, ctxt->myDoc);
714
715 /*
716 * Grab the encoding if it was added on-the-fly
717 */
718 if ((ctxt->encoding != NULL) && (ctxt->myDoc != NULL) &&
719 (ctxt->myDoc->encoding == NULL)) {
720 ctxt->myDoc->encoding = ctxt->encoding;
721 ctxt->encoding = NULL;
722 }
723 if ((ctxt->inputTab[0]->encoding != NULL) && (ctxt->myDoc != NULL) &&
724 (ctxt->myDoc->encoding == NULL)) {
725 ctxt->myDoc->encoding = xmlStrdup(ctxt->inputTab[0]->encoding);
726 }
727 if ((ctxt->charset != XML_CHAR_ENCODING_NONE) && (ctxt->myDoc != NULL) &&
728 (ctxt->myDoc->charset == XML_CHAR_ENCODING_NONE)) {
729 ctxt->myDoc->charset = ctxt->charset;
730 }
731}
732
733/**
734 * attribute:
735 * @ctx: the user data (XML parser context)
736 * @fullname: The attribute name, including namespace prefix
737 * @value: The attribute value
738 *
739 * Handle an attribute that has been read by the parser.
740 * The default handling is to convert the attribute into an
741 * DOM subtree and past it in a new xmlAttr element added to
742 * the element.
743 */
744void
745attribute(void *ctx, const xmlChar *fullname, const xmlChar *value)
746{
747 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
748 xmlAttrPtr ret;
749 xmlChar *name;
750 xmlChar *ns;
751 xmlChar *nval;
752 xmlNsPtr namespace;
753
754/****************
755#ifdef DEBUG_SAX
756 xmlGenericError(xmlGenericErrorContext,
757 "SAX.attribute(%s, %s)\n", fullname, value);
758#endif
759 ****************/
760 /*
761 * Split the full name into a namespace prefix and the tag name
762 */
763 name = xmlSplitQName(ctxt, fullname, &ns);
764
765 /*
766 * Do the last stage of the attribute normalization
767 * Needed for HTML too:
768 * http://www.w3.org/TR/html4/types.html#h-6.2
769 */
770 nval = xmlValidNormalizeAttributeValue(ctxt->myDoc, ctxt->node,
771 fullname, value);
772 if (nval != NULL)
773 value = nval;
774
775 /*
776 * Check whether it's a namespace definition
777 */
778 if ((!ctxt->html) && (ns == NULL) &&
779 (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
780 (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
781 if (value[0] != 0) {
782 xmlURIPtr uri;
783
784 uri = xmlParseURI((const char *)value);
785 if (uri == NULL) {
786 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
787 ctxt->sax->warning(ctxt->userData,
788 "nmlns: %s not a valid URI\n", value);
789 } else {
790 if (uri->scheme == NULL) {
791 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
792 ctxt->sax->warning(ctxt->userData,
793 "nmlns: URI %s is not absolute\n", value);
794 }
795 xmlFreeURI(uri);
796 }
797 }
798
799 /* a default namespace definition */
800 xmlNewNs(ctxt->node, value, NULL);
801 if (name != NULL)
802 xmlFree(name);
803 if (nval != NULL)
804 xmlFree(nval);
805 return;
806 }
807 if ((!ctxt->html) &&
808 (ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
809 (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
810 /*
811 * Validate also for namespace decls, they are attributes from
812 * an XML-1.0 perspective
813 TODO ... doesn't map well with current API
814 if (ctxt->validate && ctxt->wellFormed &&
815 ctxt->myDoc && ctxt->myDoc->intSubset)
816 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
817 ctxt->node, ret, value);
818 */
819 /* a standard namespace definition */
820 xmlNewNs(ctxt->node, value, name);
821 xmlFree(ns);
822 if (name != NULL)
823 xmlFree(name);
824 if (nval != NULL)
825 xmlFree(nval);
826 return;
827 }
828
829 if (ns != NULL)
830 namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, ns);
831 else {
832 namespace = NULL;
833 }
834
835 /* !!!!!! <a toto:arg="" xmlns:toto="http://toto.com"> */
836 ret = xmlNewNsProp(ctxt->node, namespace, name, NULL);
837
838 if (ret != NULL) {
839 if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
840 xmlNodePtr tmp;
841
842 ret->children = xmlStringGetNodeList(ctxt->myDoc, value);
843 tmp = ret->children;
844 while (tmp != NULL) {
845 tmp->parent = (xmlNodePtr) ret;
846 if (tmp->next == NULL)
847 ret->last = tmp;
848 tmp = tmp->next;
849 }
850 } else if (value != NULL) {
851 ret->children = xmlNewDocText(ctxt->myDoc, value);
852 ret->last = ret->children;
853 if (ret->children != NULL)
854 ret->children->parent = (xmlNodePtr) ret;
855 }
856 }
857
858 if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed &&
859 ctxt->myDoc && ctxt->myDoc->intSubset) {
860
861 /*
862 * If we don't substitute entities, the validation should be
863 * done on a value with replaced entities anyway.
864 */
865 if (!ctxt->replaceEntities) {
866 xmlChar *val;
867
868 ctxt->depth++;
869 val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
870 0,0,0);
871 ctxt->depth--;
872 if (val == NULL)
873 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
874 ctxt->myDoc, ctxt->node, ret, value);
875 else {
876 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
877 ctxt->myDoc, ctxt->node, ret, val);
878 xmlFree(val);
879 }
880 } else {
881 ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
882 ctxt->node, ret, value);
883 }
Daniel Veillard62f313b2001-07-04 19:49:14 +0000884 } else if (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) ||
885 ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0))) {
Owen Taylor3473f882001-02-23 17:55:21 +0000886 /*
887 * when validating, the ID registration is done at the attribute
888 * validation level. Otherwise we have to do specific handling here.
889 */
890 if (xmlIsID(ctxt->myDoc, ctxt->node, ret))
891 xmlAddID(&ctxt->vctxt, ctxt->myDoc, value, ret);
892 else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret))
893 xmlAddRef(&ctxt->vctxt, ctxt->myDoc, value, ret);
894 }
895
896 if (nval != NULL)
897 xmlFree(nval);
898 if (name != NULL)
899 xmlFree(name);
900 if (ns != NULL)
901 xmlFree(ns);
902}
903
904/**
905 * startElement:
906 * @ctx: the user data (XML parser context)
907 * @fullname: The element name, including namespace prefix
908 * @atts: An array of name/value attributes pairs, NULL terminated
909 *
910 * called when an opening tag has been processed.
911 */
912void
913startElement(void *ctx, const xmlChar *fullname, const xmlChar **atts)
914{
915 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
916 xmlNodePtr ret;
917 xmlNodePtr parent = ctxt->node;
918 xmlNsPtr ns;
919 xmlChar *name;
920 xmlChar *prefix;
921 const xmlChar *att;
922 const xmlChar *value;
923 int i;
924
925#ifdef DEBUG_SAX
926 xmlGenericError(xmlGenericErrorContext,
927 "SAX.startElement(%s)\n", fullname);
928#endif
929
930 /*
931 * First check on validity:
932 */
933 if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) &&
934 ((ctxt->myDoc->intSubset == NULL) ||
935 ((ctxt->myDoc->intSubset->notations == NULL) &&
936 (ctxt->myDoc->intSubset->elements == NULL) &&
937 (ctxt->myDoc->intSubset->attributes == NULL) &&
938 (ctxt->myDoc->intSubset->entities == NULL)))) {
939 if (ctxt->vctxt.error != NULL) {
940 ctxt->vctxt.error(ctxt->vctxt.userData,
941 "Validation failed: no DTD found !\n");
942 }
943 ctxt->validate = 0;
944 }
945
946
947 /*
948 * Split the full name into a namespace prefix and the tag name
949 */
950 name = xmlSplitQName(ctxt, fullname, &prefix);
951
952
953 /*
954 * Note : the namespace resolution is deferred until the end of the
955 * attributes parsing, since local namespace can be defined as
956 * an attribute at this level.
957 */
958 ret = xmlNewDocNode(ctxt->myDoc, NULL, name, NULL);
959 if (ret == NULL) return;
960 if (ctxt->myDoc->children == NULL) {
961#ifdef DEBUG_SAX_TREE
962 xmlGenericError(xmlGenericErrorContext, "Setting %s as root\n", name);
963#endif
964 xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
965 } else if (parent == NULL) {
966 parent = ctxt->myDoc->children;
967 }
968 ctxt->nodemem = -1;
Daniel Veillardd9bad132001-07-23 19:39:43 +0000969 if (ctxt->linenumbers) {
970 if (ctxt->input != NULL)
971 ret->content = (void *) (long) ctxt->input->line;
972 }
Owen Taylor3473f882001-02-23 17:55:21 +0000973
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{
Daniel Veillard7583a592001-07-08 13:15:55 +00001600 static int xmlSAXInitialized = 0;
1601 if (xmlSAXInitialized)
1602 return;
1603
Owen Taylor3473f882001-02-23 17:55:21 +00001604 xmlDefaultSAXHandler.internalSubset = internalSubset;
1605 xmlDefaultSAXHandler.externalSubset = externalSubset;
1606 xmlDefaultSAXHandler.isStandalone = isStandalone;
1607 xmlDefaultSAXHandler.hasInternalSubset = hasInternalSubset;
1608 xmlDefaultSAXHandler.hasExternalSubset = hasExternalSubset;
1609 xmlDefaultSAXHandler.resolveEntity = resolveEntity;
1610 xmlDefaultSAXHandler.getEntity = getEntity;
1611 xmlDefaultSAXHandler.getParameterEntity = getParameterEntity;
1612 xmlDefaultSAXHandler.entityDecl = entityDecl;
1613 xmlDefaultSAXHandler.attributeDecl = attributeDecl;
1614 xmlDefaultSAXHandler.elementDecl = elementDecl;
1615 xmlDefaultSAXHandler.notationDecl = notationDecl;
1616 xmlDefaultSAXHandler.unparsedEntityDecl = unparsedEntityDecl;
1617 xmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
1618 xmlDefaultSAXHandler.startDocument = startDocument;
1619 xmlDefaultSAXHandler.endDocument = endDocument;
1620 xmlDefaultSAXHandler.startElement = startElement;
1621 xmlDefaultSAXHandler.endElement = endElement;
1622 xmlDefaultSAXHandler.reference = reference;
1623 xmlDefaultSAXHandler.characters = characters;
1624 xmlDefaultSAXHandler.cdataBlock = cdataBlock;
1625 xmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
1626 xmlDefaultSAXHandler.processingInstruction = processingInstruction;
1627 xmlDefaultSAXHandler.comment = comment;
1628 if (xmlGetWarningsDefaultValue == 0)
1629 xmlDefaultSAXHandler.warning = NULL;
1630 else
1631 xmlDefaultSAXHandler.warning = xmlParserWarning;
1632 xmlDefaultSAXHandler.error = xmlParserError;
1633 xmlDefaultSAXHandler.fatalError = xmlParserError;
Daniel Veillard7583a592001-07-08 13:15:55 +00001634
1635 xmlSAXInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001636}
1637
Daniel Veillardeae522a2001-04-23 13:41:34 +00001638#ifdef LIBXML_HTML_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001639/*
1640 * Default handler for HTML, builds the DOM tree
1641 */
1642xmlSAXHandler htmlDefaultSAXHandler = {
1643 internalSubset,
1644 NULL,
1645 NULL,
1646 NULL,
1647 NULL,
1648 getEntity,
1649 NULL,
1650 NULL,
1651 NULL,
1652 NULL,
1653 NULL,
1654 setDocumentLocator,
1655 startDocument,
1656 endDocument,
1657 startElement,
1658 endElement,
1659 NULL,
1660 characters,
1661 ignorableWhitespace,
1662 NULL,
1663 comment,
1664 xmlParserWarning,
1665 xmlParserError,
1666 xmlParserError,
1667 getParameterEntity,
1668 cdataBlock,
1669 NULL,
1670};
1671
1672/**
1673 * htmlDefaultSAXHandlerInit:
1674 *
1675 * Initialize the default SAX handler
1676 */
1677void
1678htmlDefaultSAXHandlerInit(void)
1679{
Daniel Veillard7583a592001-07-08 13:15:55 +00001680 static int htmlSAXInitialized = 0;
1681 if (htmlSAXInitialized)
1682 return;
1683
Owen Taylor3473f882001-02-23 17:55:21 +00001684 htmlDefaultSAXHandler.internalSubset = internalSubset;
1685 htmlDefaultSAXHandler.externalSubset = NULL;
1686 htmlDefaultSAXHandler.isStandalone = NULL;
1687 htmlDefaultSAXHandler.hasInternalSubset = NULL;
1688 htmlDefaultSAXHandler.hasExternalSubset = NULL;
1689 htmlDefaultSAXHandler.resolveEntity = NULL;
1690 htmlDefaultSAXHandler.getEntity = getEntity;
1691 htmlDefaultSAXHandler.getParameterEntity = NULL;
1692 htmlDefaultSAXHandler.entityDecl = NULL;
1693 htmlDefaultSAXHandler.attributeDecl = NULL;
1694 htmlDefaultSAXHandler.elementDecl = NULL;
1695 htmlDefaultSAXHandler.notationDecl = NULL;
1696 htmlDefaultSAXHandler.unparsedEntityDecl = NULL;
1697 htmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
1698 htmlDefaultSAXHandler.startDocument = startDocument;
1699 htmlDefaultSAXHandler.endDocument = endDocument;
1700 htmlDefaultSAXHandler.startElement = startElement;
1701 htmlDefaultSAXHandler.endElement = endElement;
1702 htmlDefaultSAXHandler.reference = NULL;
1703 htmlDefaultSAXHandler.characters = characters;
1704 htmlDefaultSAXHandler.cdataBlock = cdataBlock;
1705 htmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
1706 htmlDefaultSAXHandler.processingInstruction = NULL;
1707 htmlDefaultSAXHandler.comment = comment;
1708 htmlDefaultSAXHandler.warning = xmlParserWarning;
1709 htmlDefaultSAXHandler.error = xmlParserError;
1710 htmlDefaultSAXHandler.fatalError = xmlParserError;
Daniel Veillard7583a592001-07-08 13:15:55 +00001711
1712 htmlSAXInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001713}
Daniel Veillardeae522a2001-04-23 13:41:34 +00001714#endif /* LIBXML_HTML_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001715
Daniel Veillardeae522a2001-04-23 13:41:34 +00001716#ifdef LIBXML_DOCB_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001717/*
Daniel Veillardeae522a2001-04-23 13:41:34 +00001718 * Default handler for SGML DocBook, builds the DOM tree
Owen Taylor3473f882001-02-23 17:55:21 +00001719 */
Daniel Veillardeae522a2001-04-23 13:41:34 +00001720xmlSAXHandler docbDefaultSAXHandler = {
Owen Taylor3473f882001-02-23 17:55:21 +00001721 internalSubset,
Daniel Veillard61b33d52001-04-24 13:55:12 +00001722 isStandalone,
1723 hasInternalSubset,
1724 hasExternalSubset,
1725 resolveEntity,
Owen Taylor3473f882001-02-23 17:55:21 +00001726 getEntity,
Daniel Veillard61b33d52001-04-24 13:55:12 +00001727 entityDecl,
Owen Taylor3473f882001-02-23 17:55:21 +00001728 NULL,
1729 NULL,
1730 NULL,
1731 NULL,
1732 setDocumentLocator,
1733 startDocument,
1734 endDocument,
1735 startElement,
1736 endElement,
Daniel Veillard1034da22001-04-25 19:06:28 +00001737 reference,
Owen Taylor3473f882001-02-23 17:55:21 +00001738 characters,
1739 ignorableWhitespace,
1740 NULL,
1741 comment,
1742 xmlParserWarning,
1743 xmlParserError,
1744 xmlParserError,
1745 getParameterEntity,
1746 NULL,
1747 NULL,
1748};
1749
1750/**
Daniel Veillardeae522a2001-04-23 13:41:34 +00001751 * docbDefaultSAXHandlerInit:
Owen Taylor3473f882001-02-23 17:55:21 +00001752 *
1753 * Initialize the default SAX handler
1754 */
1755void
Daniel Veillardeae522a2001-04-23 13:41:34 +00001756docbDefaultSAXHandlerInit(void)
Owen Taylor3473f882001-02-23 17:55:21 +00001757{
Daniel Veillard7583a592001-07-08 13:15:55 +00001758 static int docbSAXInitialized = 0;
1759 if (docbSAXInitialized)
1760 return;
1761
Daniel Veillardeae522a2001-04-23 13:41:34 +00001762 docbDefaultSAXHandler.internalSubset = internalSubset;
1763 docbDefaultSAXHandler.externalSubset = NULL;
Daniel Veillard61b33d52001-04-24 13:55:12 +00001764 docbDefaultSAXHandler.isStandalone = isStandalone;
1765 docbDefaultSAXHandler.hasInternalSubset = hasInternalSubset;
1766 docbDefaultSAXHandler.hasExternalSubset = hasExternalSubset;
1767 docbDefaultSAXHandler.resolveEntity = resolveEntity;
Daniel Veillardeae522a2001-04-23 13:41:34 +00001768 docbDefaultSAXHandler.getEntity = getEntity;
1769 docbDefaultSAXHandler.getParameterEntity = NULL;
Daniel Veillard61b33d52001-04-24 13:55:12 +00001770 docbDefaultSAXHandler.entityDecl = entityDecl;
Daniel Veillardeae522a2001-04-23 13:41:34 +00001771 docbDefaultSAXHandler.attributeDecl = NULL;
1772 docbDefaultSAXHandler.elementDecl = NULL;
1773 docbDefaultSAXHandler.notationDecl = NULL;
1774 docbDefaultSAXHandler.unparsedEntityDecl = NULL;
1775 docbDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
1776 docbDefaultSAXHandler.startDocument = startDocument;
1777 docbDefaultSAXHandler.endDocument = endDocument;
1778 docbDefaultSAXHandler.startElement = startElement;
1779 docbDefaultSAXHandler.endElement = endElement;
Daniel Veillard1034da22001-04-25 19:06:28 +00001780 docbDefaultSAXHandler.reference = reference;
Daniel Veillardeae522a2001-04-23 13:41:34 +00001781 docbDefaultSAXHandler.characters = characters;
1782 docbDefaultSAXHandler.cdataBlock = NULL;
1783 docbDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
1784 docbDefaultSAXHandler.processingInstruction = NULL;
1785 docbDefaultSAXHandler.comment = comment;
1786 docbDefaultSAXHandler.warning = xmlParserWarning;
1787 docbDefaultSAXHandler.error = xmlParserError;
1788 docbDefaultSAXHandler.fatalError = xmlParserError;
Daniel Veillard7583a592001-07-08 13:15:55 +00001789
1790 docbSAXInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001791}
Daniel Veillardeae522a2001-04-23 13:41:34 +00001792
1793#endif /* LIBXML_DOCB_ENABLED */