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