blob: 7f9ea18a73564348e3b2395fbcb887ae626fec1e [file] [log] [blame]
Daniel Veillard260a68f1998-08-13 03:39:55 +00001/*
2 * SAX.c : Default SAX handler to build a tree.
Daniel Veillard97b58771998-10-20 06:14:16 +00003 *
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00004 * See Copyright for the status of this software.
5 *
Daniel Veillard97b58771998-10-20 06:14:16 +00006 * Daniel Veillard <Daniel.Veillard@w3.org>
Daniel Veillard260a68f1998-08-13 03:39:55 +00007 */
8
9#include <stdio.h>
Seth Alvese7f12e61998-10-01 20:51:15 +000010#include <stdlib.h>
Daniel Veillard260a68f1998-08-13 03:39:55 +000011#include "tree.h"
12#include "parser.h"
Daniel Veillard517752b1999-04-05 12:20:10 +000013#include "parserInternals.h"
14#include "valid.h"
Daniel Veillardccb09631998-10-27 06:21:04 +000015#include "entities.h"
Daniel Veillardd109e371999-03-05 06:26:45 +000016#include "xml-error.h"
Daniel Veillard260a68f1998-08-13 03:39:55 +000017
18/* #define DEBUG_SAX */
19
Daniel Veillard97b58771998-10-20 06:14:16 +000020/**
21 * getPublicId:
22 * @ctxt: An XML parser context
23 *
Daniel Veillard260a68f1998-08-13 03:39:55 +000024 * Return the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
Daniel Veillard97b58771998-10-20 06:14:16 +000025 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000026 * Returns a CHAR *
Daniel Veillard260a68f1998-08-13 03:39:55 +000027 */
Daniel Veillard97b58771998-10-20 06:14:16 +000028const CHAR *
29getPublicId(xmlParserCtxtPtr ctxt)
30{
Daniel Veillard260a68f1998-08-13 03:39:55 +000031 return(NULL);
32}
33
Daniel Veillard97b58771998-10-20 06:14:16 +000034/**
35 * getSystemId:
36 * @ctxt: An XML parser context
37 *
Daniel Veillard260a68f1998-08-13 03:39:55 +000038 * Return the system ID, basically URI or filename e.g.
Daniel Veillard97b58771998-10-20 06:14:16 +000039 * http://www.sgmlsource.com/dtds/memo.dtd
40 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000041 * Returns a CHAR *
Daniel Veillard260a68f1998-08-13 03:39:55 +000042 */
Daniel Veillard97b58771998-10-20 06:14:16 +000043const CHAR *
44getSystemId(xmlParserCtxtPtr ctxt)
45{
Daniel Veillard260a68f1998-08-13 03:39:55 +000046 return(ctxt->input->filename);
47}
48
Daniel Veillard97b58771998-10-20 06:14:16 +000049/**
50 * getLineNumber:
51 * @ctxt: An XML parser context
52 *
Daniel Veillard260a68f1998-08-13 03:39:55 +000053 * Return the line number of the current parsing point.
Daniel Veillard97b58771998-10-20 06:14:16 +000054 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000055 * Returns an int
Daniel Veillard260a68f1998-08-13 03:39:55 +000056 */
Daniel Veillard97b58771998-10-20 06:14:16 +000057int
58getLineNumber(xmlParserCtxtPtr ctxt)
59{
Daniel Veillard260a68f1998-08-13 03:39:55 +000060 return(ctxt->input->line);
61}
Daniel Veillard97b58771998-10-20 06:14:16 +000062
63/**
64 * getColumnNumber:
65 * @ctxt: An XML parser context
66 *
Daniel Veillard260a68f1998-08-13 03:39:55 +000067 * Return the column number of the current parsing point.
Daniel Veillard97b58771998-10-20 06:14:16 +000068 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000069 * Returns an int
Daniel Veillard260a68f1998-08-13 03:39:55 +000070 */
Daniel Veillard97b58771998-10-20 06:14:16 +000071int
72getColumnNumber(xmlParserCtxtPtr ctxt)
73{
Daniel Veillard260a68f1998-08-13 03:39:55 +000074 return(ctxt->input->col);
75}
76
77/*
78 * The default SAX Locator.
79 */
80
81xmlSAXLocator xmlDefaultSAXLocator = {
82 getPublicId, getSystemId, getLineNumber, getColumnNumber
83};
84
Daniel Veillard97b58771998-10-20 06:14:16 +000085/**
Daniel Veillard517752b1999-04-05 12:20:10 +000086 * isStandalone:
87 * @ctxt: An XML parser context
88 *
89 * Is this document tagged standalone ?
90 *
91 * Returns 1 if true
92 */
93int
94isStandalone(xmlParserCtxtPtr ctxt)
95{
96 return(ctxt->myDoc->standalone == 1);
97}
98
99/**
100 * hasInternalSubset:
101 * @ctxt: An XML parser context
102 *
103 * Does this document has an internal subset
104 *
105 * Returns 1 if true
106 */
107int
108hasInternalSubset(xmlParserCtxtPtr ctxt)
109{
110 return(ctxt->myDoc->intSubset != NULL);
111}
112
113/**
114 * hasExternalSubset:
115 * @ctxt: An XML parser context
116 *
117 * Does this document has an external subset
118 *
119 * Returns 1 if true
120 */
121int
122hasExternalSubset(xmlParserCtxtPtr ctxt)
123{
124 return(ctxt->myDoc->extSubset != NULL);
125}
126
127/**
128 * hasInternalSubset:
129 * @ctxt: An XML parser context
130 *
131 * Does this document has an internal subset
132 */
133void
134internalSubset(xmlParserCtxtPtr ctxt, const CHAR *name,
135 const CHAR *ExternalID, const CHAR *SystemID)
136{
137#ifdef DEBUG_SAX
138 fprintf(stderr, "SAX.internalSubset(%s, %s, %s)\n",
139 name, ExternalID, SystemID);
140#endif
141 xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
142}
143
144/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000145 * resolveEntity:
146 * @ctxt: An XML parser context
147 * @publicId: The public ID of the entity
148 * @systemId: The system ID of the entity
149 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000150 * Special entity resolver, better left to the parser, it has
151 * more context than the application layer.
Daniel Veillardccb09631998-10-27 06:21:04 +0000152 * The default behaviour is to NOT resolve the entities, in that case
153 * the ENTITY_REF nodes are built in the structure (and the parameter
154 * values).
Daniel Veillard97b58771998-10-20 06:14:16 +0000155 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000156 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000157 */
Daniel Veillard97b58771998-10-20 06:14:16 +0000158xmlParserInputPtr
159resolveEntity(xmlParserCtxtPtr ctxt, const CHAR *publicId, const CHAR *systemId)
160{
Daniel Veillard260a68f1998-08-13 03:39:55 +0000161
162#ifdef DEBUG_SAX
163 fprintf(stderr, "SAX.resolveEntity(%s, %s)\n", publicId, systemId);
164#endif
Daniel Veillardccb09631998-10-27 06:21:04 +0000165
Daniel Veillard517752b1999-04-05 12:20:10 +0000166 /*
167 * TODO : not 100% sure that the appropriate handling in that case.
168 */
Daniel Veillard260a68f1998-08-13 03:39:55 +0000169 return(NULL);
170}
171
Daniel Veillard97b58771998-10-20 06:14:16 +0000172/**
Daniel Veillard517752b1999-04-05 12:20:10 +0000173 * getEntity:
174 * @ctxt: An XML parser context
175 * @name: The entity name
176 *
177 * Get an entity by name
178 *
179 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
180 */
181xmlEntityPtr
182getEntity(xmlParserCtxtPtr ctxt, const CHAR *name)
183{
184 xmlEntityPtr ret;
185
186#ifdef DEBUG_SAX
187 fprintf(stderr, "SAX.getEntity(%s)\n", name);
188#endif
189
190 ret = xmlGetDocEntity(ctxt->myDoc, name);
191 return(ret);
192}
193
194
195/**
196 * entityDecl:
197 * @ctxt: An XML parser context
198 * @name: the entity name
199 * @type: the entity type
200 * @publicId: The public ID of the entity
201 * @systemId: The system ID of the entity
202 * @content: the entity value (without processing).
203 *
204 * An entity definition has been parsed
205 */
206void
207entityDecl(xmlParserCtxtPtr ctxt, const CHAR *name, int type,
208 const CHAR *publicId, const CHAR *systemId, CHAR *content)
209{
210
211#ifdef DEBUG_SAX
212 fprintf(stderr, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
213 name, type, publicId, systemId, content);
214#endif
215 xmlAddDocEntity(ctxt->myDoc, name, type, publicId, systemId, content);
216}
217
218/**
219 * attributeDecl:
220 * @ctxt: An XML parser context
221 * @name: the attribute name
222 * @type: the attribute type
223 * @publicId: The public ID of the attribute
224 * @systemId: The system ID of the attribute
225 * @content: the attribute value (without processing).
226 *
227 * An attribute definition has been parsed
228 */
229void
230attributeDecl(xmlParserCtxtPtr ctxt, const CHAR *elem, const CHAR *name,
231 int type, int def, const CHAR *defaultValue,
232 xmlEnumerationPtr tree)
233{
234
235#ifdef DEBUG_SAX
236 fprintf(stderr, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
237 elem, name, type, def, defaultValue);
238#endif
239 xmlAddAttributeDecl(ctxt->myDoc->intSubset, elem, name, type, def,
240 defaultValue, tree);
241}
242
243/**
244 * elementDecl:
245 * @ctxt: An XML parser context
246 * @name: the element name
247 * @type: the element type
248 * @publicId: The public ID of the element
249 * @systemId: The system ID of the element
250 * @content: the element value (without processing).
251 *
252 * An element definition has been parsed
253 */
254void
255elementDecl(xmlParserCtxtPtr ctxt, const CHAR *name, int type,
256 xmlElementContentPtr content)
257{
258
259#ifdef DEBUG_SAX
260 fprintf(stderr, "SAX.elementDecl(%s, %d, ...)\n",
261 name, type);
262#endif
263 xmlAddElementDecl(ctxt->myDoc->intSubset, name, type, content);
264}
265
266/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000267 * notationDecl:
268 * @ctxt: An XML parser context
269 * @name: The name of the notation
270 * @publicId: The public ID of the entity
271 * @systemId: The system ID of the entity
272 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000273 * What to do when a notation declaration has been parsed.
274 * TODO Not handled currently.
275 */
Daniel Veillard97b58771998-10-20 06:14:16 +0000276void
277notationDecl(xmlParserCtxtPtr ctxt, const CHAR *name,
278 const CHAR *publicId, const CHAR *systemId)
279{
Daniel Veillard260a68f1998-08-13 03:39:55 +0000280#ifdef DEBUG_SAX
281 fprintf(stderr, "SAX.notationDecl(%s, %s, %s)\n", name, publicId, systemId);
282#endif
Daniel Veillard517752b1999-04-05 12:20:10 +0000283 xmlAddNotationDecl(ctxt->myDoc->intSubset, name, publicId, systemId);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000284}
285
Daniel Veillard97b58771998-10-20 06:14:16 +0000286/**
287 * unparsedEntityDecl:
288 * @ctxt: An XML parser context
289 * @name: The name of the entity
290 * @publicId: The public ID of the entity
291 * @systemId: The system ID of the entity
292 * @notationName: the name of the notation
293 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000294 * What to do when an unparsed entity declaration is parsed
295 * TODO Create an Entity node.
296 */
Daniel Veillard97b58771998-10-20 06:14:16 +0000297void
298unparsedEntityDecl(xmlParserCtxtPtr ctxt, const CHAR *name,
299 const CHAR *publicId, const CHAR *systemId,
300 const CHAR *notationName)
301{
Daniel Veillard260a68f1998-08-13 03:39:55 +0000302#ifdef DEBUG_SAX
303 fprintf(stderr, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
304 name, publicId, systemId, notationName);
305#endif
306}
307
Daniel Veillard97b58771998-10-20 06:14:16 +0000308/**
309 * setDocumentLocator:
310 * @ctxt: An XML parser context
311 * @loc: A SAX Locator
312 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000313 * Receive the document locator at startup, actually xmlDefaultSAXLocator
314 * Everything is available on the context, so this is useless in our case.
315 */
Daniel Veillard97b58771998-10-20 06:14:16 +0000316void
317setDocumentLocator(xmlParserCtxtPtr ctxt, xmlSAXLocatorPtr loc)
318{
Daniel Veillard260a68f1998-08-13 03:39:55 +0000319#ifdef DEBUG_SAX
320 fprintf(stderr, "SAX.setDocumentLocator()\n");
321#endif
322}
323
Daniel Veillard97b58771998-10-20 06:14:16 +0000324/**
325 * startDocument:
326 * @ctxt: An XML parser context
327 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000328 * called when the document start being processed.
329 */
Daniel Veillard97b58771998-10-20 06:14:16 +0000330void
331startDocument(xmlParserCtxtPtr ctxt)
332{
Daniel Veillard517752b1999-04-05 12:20:10 +0000333 xmlDocPtr doc;
334
Daniel Veillard260a68f1998-08-13 03:39:55 +0000335#ifdef DEBUG_SAX
336 fprintf(stderr, "SAX.startDocument()\n");
337#endif
Daniel Veillard517752b1999-04-05 12:20:10 +0000338 doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
339 if (doc != NULL) {
340 if (ctxt->encoding != NULL)
341 doc->encoding = xmlStrdup(ctxt->encoding);
342 else
343 doc->encoding = NULL;
344 doc->standalone = ctxt->standalone;
345 }
Daniel Veillard260a68f1998-08-13 03:39:55 +0000346}
347
Daniel Veillard97b58771998-10-20 06:14:16 +0000348/**
349 * endDocument:
350 * @ctxt: An XML parser context
351 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000352 * called when the document end has been detected.
353 */
Daniel Veillard97b58771998-10-20 06:14:16 +0000354void
355endDocument(xmlParserCtxtPtr ctxt)
356{
Daniel Veillard260a68f1998-08-13 03:39:55 +0000357#ifdef DEBUG_SAX
358 fprintf(stderr, "SAX.endDocument()\n");
359#endif
360}
361
Daniel Veillard97b58771998-10-20 06:14:16 +0000362/**
Daniel Veillard517752b1999-04-05 12:20:10 +0000363 * attribute:
364 * @ctxt: An XML parser context
365 * @name: The attribute name
366 * @value: The attribute value
367 *
368 * Handle an attribute that has been read by the parser.
369 * The default handling is to convert the attribute into an
370 * DOM subtree and past it in a new xmlAttr element added to
371 * the element.
372 */
373void
374attribute(xmlParserCtxtPtr ctxt, const CHAR *fullname, const CHAR *value)
375{
376 xmlAttrPtr ret;
377 CHAR *name;
378 CHAR *ns;
379
380/****************
381#ifdef DEBUG_SAX
382 fprintf(stderr, "SAX.attribute(%s, %s)\n", fullname, value);
383#endif
384 ****************/
385 /*
386 * Split the full name into a namespace prefix and the tag name
387 */
388 name = xmlSplitQName(fullname, &ns);
389
390 /*
391 * Check whether it's a namespace definition
392 */
393 if ((ns == NULL) &&
394 (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
395 (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
396 /* a default namespace definition */
397 xmlNewNs(ctxt->node, value, NULL);
398 if (name != NULL)
399 free(name);
400 return;
401 }
402 if ((ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
403 (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
404 /* a standard namespace definition */
405 xmlNewNs(ctxt->node, value, name);
406 free(ns);
407 if (name != NULL)
408 free(name);
409 return;
410 }
411
412 ret = xmlNewProp(ctxt->node, name, NULL);
413 if (ret != NULL)
414 ret->val = xmlStringGetNodeList(ctxt->myDoc, value);
415 if (name != NULL)
416 free(name);
417 if (ns != NULL)
418 free(ns);
419}
420
421/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000422 * startElement:
423 * @ctxt: An XML parser context
424 * @name: The element name
Daniel Veillard517752b1999-04-05 12:20:10 +0000425 * @atts: An array of name/value attributes pairs, NULL terminated
Daniel Veillard97b58771998-10-20 06:14:16 +0000426 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000427 * called when an opening tag has been processed.
428 * TODO We currently have a small pblm with the arguments ...
429 */
Daniel Veillard97b58771998-10-20 06:14:16 +0000430void
Daniel Veillard517752b1999-04-05 12:20:10 +0000431startElement(xmlParserCtxtPtr ctxt, const CHAR *fullname, const CHAR **atts)
Daniel Veillard97b58771998-10-20 06:14:16 +0000432{
Daniel Veillard517752b1999-04-05 12:20:10 +0000433 xmlNodePtr ret;
434 xmlNodePtr parent = ctxt->node;
435 xmlNsPtr ns;
436 CHAR *name;
437 CHAR *prefix;
438 const CHAR *att;
439 const CHAR *value;
440
441 int i;
442
Daniel Veillard260a68f1998-08-13 03:39:55 +0000443#ifdef DEBUG_SAX
Daniel Veillard517752b1999-04-05 12:20:10 +0000444 fprintf(stderr, "SAX.startElement(%s)\n", fullname);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000445#endif
Daniel Veillard517752b1999-04-05 12:20:10 +0000446 /*
447 * Split the full name into a namespace prefix and the tag name
448 */
449 name = xmlSplitQName(fullname, &prefix);
450
451
452 /*
453 * Note : the namespace resolution is deferred until the end of the
454 * attributes parsing, since local namespace can be defined as
455 * an attribute at this level.
456 */
457 ret = xmlNewDocNode(ctxt->myDoc, NULL, name, NULL);
458 if (ret == NULL) return;
459 if (ctxt->myDoc->root == NULL)
460 ctxt->myDoc->root = ret;
461
462 /*
463 * We are parsing a new node.
464 */
465 nodePush(ctxt, ret);
466
467 /*
468 * Link the child element
469 */
470 if (parent != NULL)
471 xmlAddChild(parent, ctxt->node);
472
473 /*
474 * process all the attributes.
475 */
476 if (atts != NULL) {
477 i = 0;
478 att = atts[i++];
479 value = atts[i++];
480 while ((att != NULL) && (value != NULL)) {
481 /*
482 * Handle one pair of attribute/value
483 */
484 attribute(ctxt, att, value);
485
486 /*
487 * Next ones
488 */
489 att = atts[i++];
490 value = atts[i++];
491 }
492 }
493
494 /*
495 * Search the namespace, note that since the attributes have been
496 * processed, the local namespaces are available.
497 */
498 ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
499 if ((ns == NULL) && (parent != NULL))
500 ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
501 xmlSetNs(ret, ns);
502
503 if (prefix != NULL)
504 free(prefix);
505 if (name != NULL)
506 free(name);
507
Daniel Veillard260a68f1998-08-13 03:39:55 +0000508}
509
Daniel Veillard97b58771998-10-20 06:14:16 +0000510/**
511 * endElement:
512 * @ctxt: An XML parser context
513 * @name: The element name
514 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000515 * called when the end of an element has been detected.
516 */
Daniel Veillard97b58771998-10-20 06:14:16 +0000517void
518endElement(xmlParserCtxtPtr ctxt, const CHAR *name)
519{
Daniel Veillard517752b1999-04-05 12:20:10 +0000520 xmlParserNodeInfo node_info;
521 xmlNodePtr cur = ctxt->node;
522
Daniel Veillard260a68f1998-08-13 03:39:55 +0000523#ifdef DEBUG_SAX
Daniel Veillard517752b1999-04-05 12:20:10 +0000524 if (name == NULL)
525 fprintf(stderr, "SAX.endElement(NULL)\n");
526 else
527 fprintf(stderr, "SAX.endElement(%s)\n", name);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000528#endif
Daniel Veillard517752b1999-04-05 12:20:10 +0000529
530 /* Capture end position and add node */
531 if (cur != NULL && ctxt->record_info) {
532 node_info.end_pos = ctxt->input->cur - ctxt->input->base;
533 node_info.end_line = ctxt->input->line;
534 node_info.node = cur;
535 xmlParserAddNodeInfo(ctxt, &node_info);
536 }
537
538 /*
539 * end of parsing of this node.
540 */
541 nodePop(ctxt);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000542}
543
Daniel Veillard97b58771998-10-20 06:14:16 +0000544/**
Daniel Veillard517752b1999-04-05 12:20:10 +0000545 * reference:
Daniel Veillard11e00581998-10-24 18:27:49 +0000546 * @ctxt: An XML parser context
Daniel Veillard517752b1999-04-05 12:20:10 +0000547 * @name: The entity name
Daniel Veillard11e00581998-10-24 18:27:49 +0000548 *
Daniel Veillard517752b1999-04-05 12:20:10 +0000549 * called when an entity reference is detected.
Daniel Veillard11e00581998-10-24 18:27:49 +0000550 */
551void
Daniel Veillard517752b1999-04-05 12:20:10 +0000552reference(xmlParserCtxtPtr ctxt, const CHAR *name)
Daniel Veillard11e00581998-10-24 18:27:49 +0000553{
Daniel Veillard517752b1999-04-05 12:20:10 +0000554 xmlNodePtr ret;
555
Daniel Veillard11e00581998-10-24 18:27:49 +0000556#ifdef DEBUG_SAX
Daniel Veillard517752b1999-04-05 12:20:10 +0000557 fprintf(stderr, "SAX.reference(%s)\n", name);
Daniel Veillard11e00581998-10-24 18:27:49 +0000558#endif
Daniel Veillard517752b1999-04-05 12:20:10 +0000559 ret = xmlNewReference(ctxt->myDoc, name);
560 xmlAddChild(ctxt->node, ret);
Daniel Veillard11e00581998-10-24 18:27:49 +0000561}
562
563/**
Daniel Veillard97b58771998-10-20 06:14:16 +0000564 * characters:
565 * @ctxt: An XML parser context
566 * @ch: a CHAR string
Daniel Veillard97b58771998-10-20 06:14:16 +0000567 * @len: the number of CHAR
568 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000569 * receiving some chars from the parser.
570 * Question: how much at a time ???
571 */
Daniel Veillard97b58771998-10-20 06:14:16 +0000572void
Daniel Veillard517752b1999-04-05 12:20:10 +0000573characters(xmlParserCtxtPtr ctxt, const CHAR *ch, int len)
Daniel Veillard97b58771998-10-20 06:14:16 +0000574{
Daniel Veillard260a68f1998-08-13 03:39:55 +0000575 xmlNodePtr lastChild;
576
577#ifdef DEBUG_SAX
Daniel Veillard517752b1999-04-05 12:20:10 +0000578 fprintf(stderr, "SAX.characters(%.30s, %d)\n", ch, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000579#endif
580 /*
581 * Handle the data if any. If there is no child
582 * add it as content, otherwise if the last child is text,
583 * concatenate it, else create a new node of type text.
584 */
585
586 lastChild = xmlGetLastChild(ctxt->node);
587 if (lastChild == NULL)
Daniel Veillard517752b1999-04-05 12:20:10 +0000588 xmlNodeAddContentLen(ctxt->node, ch, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000589 else {
590 if (xmlNodeIsText(lastChild))
Daniel Veillard517752b1999-04-05 12:20:10 +0000591 xmlTextConcat(lastChild, ch, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000592 else {
Daniel Veillard517752b1999-04-05 12:20:10 +0000593 lastChild = xmlNewTextLen(ch, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000594 xmlAddChild(ctxt->node, lastChild);
595 }
596 }
597}
598
Daniel Veillard97b58771998-10-20 06:14:16 +0000599/**
600 * ignorableWhitespace:
601 * @ctxt: An XML parser context
602 * @ch: a CHAR string
Daniel Veillard97b58771998-10-20 06:14:16 +0000603 * @len: the number of CHAR
604 *
Daniel Veillard260a68f1998-08-13 03:39:55 +0000605 * receiving some ignorable whitespaces from the parser.
606 * Question: how much at a time ???
607 */
Daniel Veillard97b58771998-10-20 06:14:16 +0000608void
Daniel Veillard517752b1999-04-05 12:20:10 +0000609ignorableWhitespace(xmlParserCtxtPtr ctxt, const CHAR *ch, int len)
Daniel Veillard97b58771998-10-20 06:14:16 +0000610{
Daniel Veillard260a68f1998-08-13 03:39:55 +0000611#ifdef DEBUG_SAX
Daniel Veillard517752b1999-04-05 12:20:10 +0000612 fprintf(stderr, "SAX.ignorableWhitespace(%.30s, %d)\n", ch, len);
Daniel Veillard260a68f1998-08-13 03:39:55 +0000613#endif
614}
615
Daniel Veillard97b58771998-10-20 06:14:16 +0000616/**
617 * processingInstruction:
618 * @ctxt: An XML parser context
619 * @target: the target name
620 * @data: the PI data's
621 * @len: the number of CHAR
622 *
623 * A processing instruction has been parsed.
Daniel Veillard260a68f1998-08-13 03:39:55 +0000624 */
Daniel Veillard97b58771998-10-20 06:14:16 +0000625void
626processingInstruction(xmlParserCtxtPtr ctxt, const CHAR *target,
627 const CHAR *data)
628{
Daniel Veillard260a68f1998-08-13 03:39:55 +0000629#ifdef DEBUG_SAX
630 fprintf(stderr, "SAX.processingInstruction(%s, %s)\n", target, data);
631#endif
632}
633
Daniel Veillard517752b1999-04-05 12:20:10 +0000634/**
635 * globalNamespace:
636 * @ctxt: An XML parser context
637 * @href: the namespace associated URN
638 * @prefix: the namespace prefix
639 *
640 * An old global namespace has been parsed.
641 */
642void
643globalNamespace(xmlParserCtxtPtr ctxt, const CHAR *href, const CHAR *prefix)
644{
645#ifdef DEBUG_SAX
646 fprintf(stderr, "SAX.globalNamespace(%s, %s)\n", href, prefix);
647#endif
648 xmlNewGlobalNs(ctxt->myDoc, href, prefix);
649}
650
651/**
652 * setNamespace:
653 * @ctxt: An XML parser context
654 * @name: the namespace prefix
655 *
656 * Set the current element namespace.
657 */
658void
659setNamespace(xmlParserCtxtPtr ctxt, const CHAR *name)
660{
661 xmlNsPtr ns;
662 xmlNodePtr parent;
663
664#ifdef DEBUG_SAX
665 fprintf(stderr, "SAX.setNamespace(%s)\n", name);
666#endif
667 ns = xmlSearchNs(ctxt->myDoc, ctxt->node, name);
668 if (ns == NULL) { /* ctxt->node may not have a parent yet ! */
669 if (ctxt->nodeNr >= 2) {
670 parent = ctxt->nodeTab[ctxt->nodeNr - 2];
671 if (parent != NULL)
672 ns = xmlSearchNs(ctxt->myDoc, parent, name);
673 }
674 }
675 xmlSetNs(ctxt->node, ns);
676}
677
678/**
679 * getNamespace:
680 * @ctxt: An XML parser context
681 *
682 * Get the current element namespace.
683 */
684xmlNsPtr
685getNamespace(xmlParserCtxtPtr ctxt)
686{
687 xmlNsPtr ret;
688
689#ifdef DEBUG_SAX
690 fprintf(stderr, "SAX.getNamespace()\n");
691#endif
692 ret = ctxt->node->ns;
693 return(ret);
694}
695
696/**
697 * checkNamespace:
698 * @ctxt: An XML parser context
699 * @namespace: the namespace to check against
700 *
701 * Check that the current element namespace is the same as the
702 * one read upon parsing.
703 */
704int
705checkNamespace(xmlParserCtxtPtr ctxt, CHAR *namespace)
706{
707 xmlNodePtr cur = ctxt->node;
708
709#ifdef DEBUG_SAX
710 fprintf(stderr, "SAX.checkNamespace(%s)\n", namespace);
711#endif
712
713 /*
714 * Check that the Name in the ETag is the same as in the STag.
715 */
716 if (namespace == NULL) {
717 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
718 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
719 ctxt->sax->error(ctxt,
720 "End tags for %s don't hold the namespace %s\n",
721 cur->name, cur->ns->prefix);
722 ctxt->wellFormed = 0;
723 }
724 } else {
725 if ((cur->ns == NULL) || (cur->ns->prefix == NULL)) {
726 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
727 ctxt->sax->error(ctxt,
728 "End tags %s holds a prefix %s not used by the open tag\n",
729 cur->name, namespace);
730 ctxt->wellFormed = 0;
731 } else if (strcmp(namespace, cur->ns->prefix)) {
732 if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
733 ctxt->sax->error(ctxt,
734 "Start and End tags for %s don't use the same namespaces: %s and %s\n",
735 cur->name, cur->ns->prefix, namespace);
736 ctxt->wellFormed = 0;
737 } else
738 return(1);
739 }
740 return(0);
741}
742
743/**
744 * namespaceDecl:
745 * @ctxt: An XML parser context
746 * @href: the namespace associated URN
747 * @prefix: the namespace prefix
748 *
749 * A namespace has been parsed.
750 */
751void
752namespaceDecl(xmlParserCtxtPtr ctxt, const CHAR *href, const CHAR *prefix)
753{
754#ifdef DEBUG_SAX
755 if (prefix == NULL)
756 fprintf(stderr, "SAX.namespaceDecl(%s, NULL)\n", href);
757 else
758 fprintf(stderr, "SAX.namespaceDecl(%s, %s)\n", href, prefix);
759#endif
760 xmlNewNs(ctxt->node, href, prefix);
761}
762
763/**
764 * comment:
765 * @ctxt: An XML parser context
766 * @value: the comment content
767 *
768 * A comment has been parsed.
769 */
770void
771comment(xmlParserCtxtPtr ctxt, const CHAR *value)
772{
773#ifdef DEBUG_SAX
774 fprintf(stderr, "SAX.comment(%s)\n", value);
775#endif
776 xmlNewDocComment(ctxt->myDoc, value);
777}
778
Daniel Veillard260a68f1998-08-13 03:39:55 +0000779xmlSAXHandler xmlDefaultSAXHandler = {
Daniel Veillard517752b1999-04-05 12:20:10 +0000780 internalSubset,
781 isStandalone,
782 hasInternalSubset,
783 hasExternalSubset,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000784 resolveEntity,
Daniel Veillard517752b1999-04-05 12:20:10 +0000785 getEntity,
786 entityDecl,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000787 notationDecl,
Daniel Veillard517752b1999-04-05 12:20:10 +0000788 attributeDecl,
789 elementDecl,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000790 unparsedEntityDecl,
791 setDocumentLocator,
792 startDocument,
793 endDocument,
794 startElement,
795 endElement,
Daniel Veillard517752b1999-04-05 12:20:10 +0000796 reference,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000797 characters,
798 ignorableWhitespace,
799 processingInstruction,
Daniel Veillard517752b1999-04-05 12:20:10 +0000800 comment,
Daniel Veillard260a68f1998-08-13 03:39:55 +0000801 xmlParserWarning,
802 xmlParserError,
803 xmlParserError,
804};
805
Daniel Veillard97b58771998-10-20 06:14:16 +0000806/**
807 * xmlDefaultSAXHandlerInit:
808 *
809 * Initialize the default SAX handler
Daniel Veillard97b58771998-10-20 06:14:16 +0000810 */
811void
812xmlDefaultSAXHandlerInit(void)
813{
Daniel Veillard517752b1999-04-05 12:20:10 +0000814 xmlDefaultSAXHandler.internalSubset = internalSubset;
815 xmlDefaultSAXHandler.isStandalone = isStandalone;
816 xmlDefaultSAXHandler.hasInternalSubset = hasInternalSubset;
817 xmlDefaultSAXHandler.hasExternalSubset = hasExternalSubset;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000818 xmlDefaultSAXHandler.resolveEntity = resolveEntity;
Daniel Veillard517752b1999-04-05 12:20:10 +0000819 xmlDefaultSAXHandler.getEntity = getEntity;
820 xmlDefaultSAXHandler.entityDecl = entityDecl;
821 xmlDefaultSAXHandler.attributeDecl = attributeDecl;
822 xmlDefaultSAXHandler.elementDecl = elementDecl;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000823 xmlDefaultSAXHandler.notationDecl = notationDecl;
824 xmlDefaultSAXHandler.unparsedEntityDecl = unparsedEntityDecl;
825 xmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
826 xmlDefaultSAXHandler.startDocument = startDocument;
827 xmlDefaultSAXHandler.endDocument = endDocument;
828 xmlDefaultSAXHandler.startElement = startElement;
829 xmlDefaultSAXHandler.endElement = endElement;
Daniel Veillard517752b1999-04-05 12:20:10 +0000830 xmlDefaultSAXHandler.reference = reference;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000831 xmlDefaultSAXHandler.characters = characters;
832 xmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
833 xmlDefaultSAXHandler.processingInstruction = processingInstruction;
Daniel Veillard517752b1999-04-05 12:20:10 +0000834 xmlDefaultSAXHandler.comment = comment;
Daniel Veillard260a68f1998-08-13 03:39:55 +0000835 xmlDefaultSAXHandler.warning = xmlParserWarning;
836 xmlDefaultSAXHandler.error = xmlParserError;
837 xmlDefaultSAXHandler.fatalError = xmlParserError;
838}