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