Annotation of XML/SAX.c, revision 1.27
1.1 daniel 1: /*
2: * SAX.c : Default SAX handler to build a tree.
1.5 daniel 3: *
1.7 daniel 4: * See Copyright for the status of this software.
5: *
1.5 daniel 6: * Daniel Veillard <Daniel.Veillard@w3.org>
1.1 daniel 7: */
8:
9: #include <stdio.h>
1.5 daniel 10: #include <stdlib.h>
1.1 daniel 11: #include "tree.h"
12: #include "parser.h"
1.10 daniel 13: #include "parserInternals.h"
14: #include "valid.h"
1.5 daniel 15: #include "entities.h"
1.9 daniel 16: #include "xml-error.h"
1.26 daniel 17: #include "debugXML.h"
1.1 daniel 18:
1.15 daniel 19: /* #define DEBUG_SAX */
1.26 daniel 20: /* #define DEBUG_SAX_TREE */
1.2 daniel 21:
1.5 daniel 22: /**
23: * getPublicId:
1.16 daniel 24: * @ctx: the user data (XML parser context)
1.5 daniel 25: *
1.1 daniel 26: * Return the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
1.5 daniel 27: *
1.8 daniel 28: * Returns a CHAR *
1.1 daniel 29: */
1.5 daniel 30: const CHAR *
1.11 daniel 31: getPublicId(void *ctx)
1.5 daniel 32: {
1.11 daniel 33: /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
1.1 daniel 34: return(NULL);
35: }
36:
1.5 daniel 37: /**
38: * getSystemId:
1.16 daniel 39: * @ctx: the user data (XML parser context)
1.5 daniel 40: *
1.12 daniel 41: * Return the system ID, basically URL or filename e.g.
1.5 daniel 42: * http://www.sgmlsource.com/dtds/memo.dtd
43: *
1.8 daniel 44: * Returns a CHAR *
1.5 daniel 45: */
46: const CHAR *
1.11 daniel 47: getSystemId(void *ctx)
1.5 daniel 48: {
1.11 daniel 49: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.2 daniel 50: return(ctxt->input->filename);
1.1 daniel 51: }
52:
1.5 daniel 53: /**
54: * getLineNumber:
1.16 daniel 55: * @ctx: the user data (XML parser context)
1.5 daniel 56: *
1.1 daniel 57: * Return the line number of the current parsing point.
1.5 daniel 58: *
1.8 daniel 59: * Returns an int
1.1 daniel 60: */
1.5 daniel 61: int
1.11 daniel 62: getLineNumber(void *ctx)
1.5 daniel 63: {
1.11 daniel 64: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.1 daniel 65: return(ctxt->input->line);
66: }
1.5 daniel 67:
68: /**
69: * getColumnNumber:
1.16 daniel 70: * @ctx: the user data (XML parser context)
1.5 daniel 71: *
1.1 daniel 72: * Return the column number of the current parsing point.
1.5 daniel 73: *
1.8 daniel 74: * Returns an int
1.1 daniel 75: */
1.5 daniel 76: int
1.11 daniel 77: getColumnNumber(void *ctx)
1.5 daniel 78: {
1.11 daniel 79: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.1 daniel 80: return(ctxt->input->col);
81: }
82:
83: /*
84: * The default SAX Locator.
85: */
86:
87: xmlSAXLocator xmlDefaultSAXLocator = {
88: getPublicId, getSystemId, getLineNumber, getColumnNumber
89: };
90:
1.5 daniel 91: /**
1.10 daniel 92: * isStandalone:
1.16 daniel 93: * @ctx: the user data (XML parser context)
1.10 daniel 94: *
95: * Is this document tagged standalone ?
96: *
97: * Returns 1 if true
98: */
99: int
1.11 daniel 100: isStandalone(void *ctx)
1.10 daniel 101: {
1.11 daniel 102: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 103: return(ctxt->myDoc->standalone == 1);
104: }
105:
106: /**
107: * hasInternalSubset:
1.16 daniel 108: * @ctx: the user data (XML parser context)
1.10 daniel 109: *
110: * Does this document has an internal subset
111: *
112: * Returns 1 if true
113: */
114: int
1.11 daniel 115: hasInternalSubset(void *ctx)
1.10 daniel 116: {
1.11 daniel 117: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 118: return(ctxt->myDoc->intSubset != NULL);
119: }
120:
121: /**
122: * hasExternalSubset:
1.16 daniel 123: * @ctx: the user data (XML parser context)
1.10 daniel 124: *
125: * Does this document has an external subset
126: *
127: * Returns 1 if true
128: */
129: int
1.11 daniel 130: hasExternalSubset(void *ctx)
1.10 daniel 131: {
1.11 daniel 132: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 133: return(ctxt->myDoc->extSubset != NULL);
134: }
135:
136: /**
1.19 veillard 137: * internalSubset:
1.16 daniel 138: * @ctx: the user data (XML parser context)
1.10 daniel 139: *
140: * Does this document has an internal subset
141: */
142: void
1.11 daniel 143: internalSubset(void *ctx, const CHAR *name,
1.10 daniel 144: const CHAR *ExternalID, const CHAR *SystemID)
145: {
1.11 daniel 146: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 147: #ifdef DEBUG_SAX
148: fprintf(stderr, "SAX.internalSubset(%s, %s, %s)\n",
149: name, ExternalID, SystemID);
150: #endif
151: xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
1.24 daniel 152: if (((ExternalID != NULL) || (SystemID != NULL)) &&
153: (ctxt->validate && ctxt->wellFormed && ctxt->myDoc)) {
154: /*
155: * Try to fetch and parse the external subset.
156: */
157: xmlDtdPtr ret = NULL;
158: xmlParserCtxtPtr dtdCtxt;
159: xmlParserInputPtr input = NULL;
160: xmlCharEncoding enc;
161:
162: dtdCtxt = xmlNewParserCtxt();
163: if (dtdCtxt == NULL) return;
164:
165: /*
166: * Ask the Entity resolver to load the damn thing
167: */
168: if ((ctxt->directory != NULL) && (dtdCtxt->directory == NULL))
169: dtdCtxt->directory = xmlStrdup(ctxt->directory);
170:
171: if ((dtdCtxt->sax != NULL) && (dtdCtxt->sax->resolveEntity != NULL))
172: input = dtdCtxt->sax->resolveEntity(dtdCtxt->userData, ExternalID,
173: SystemID);
174: if (input == NULL) {
175: xmlFreeParserCtxt(dtdCtxt);
176: return;
177: }
178:
179: /*
180: * plug some encoding conversion routines here. !!!
181: */
182: xmlPushInput(dtdCtxt, input);
183: enc = xmlDetectCharEncoding(dtdCtxt->input->cur);
184: xmlSwitchEncoding(dtdCtxt, enc);
185:
186: if (input->filename == NULL)
187: input->filename = xmlStrdup(SystemID);
188: input->line = 1;
189: input->col = 1;
190: input->base = dtdCtxt->input->cur;
191: input->cur = dtdCtxt->input->cur;
192: input->free = NULL;
193:
194: /*
195: * let's parse that entity knowing it's an external subset.
196: */
197: xmlParseExternalSubset(dtdCtxt, ExternalID, SystemID);
198:
199: if (dtdCtxt->myDoc != NULL) {
200: if (dtdCtxt->wellFormed) {
201: ret = dtdCtxt->myDoc->intSubset;
202: dtdCtxt->myDoc->intSubset = NULL;
203: } else {
204: ret = NULL;
205: }
206: xmlFreeDoc(dtdCtxt->myDoc);
207: dtdCtxt->myDoc = NULL;
208: }
209: xmlFreeParserCtxt(dtdCtxt);
210:
211: ctxt->myDoc->extSubset = ret;
1.12 daniel 212: }
1.10 daniel 213: }
214:
215: /**
1.5 daniel 216: * resolveEntity:
1.16 daniel 217: * @ctx: the user data (XML parser context)
1.5 daniel 218: * @publicId: The public ID of the entity
219: * @systemId: The system ID of the entity
220: *
1.1 daniel 221: * Special entity resolver, better left to the parser, it has
222: * more context than the application layer.
1.5 daniel 223: * The default behaviour is to NOT resolve the entities, in that case
224: * the ENTITY_REF nodes are built in the structure (and the parameter
1.6 daniel 225: * values).
1.5 daniel 226: *
1.8 daniel 227: * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
1.5 daniel 228: */
229: xmlParserInputPtr
1.11 daniel 230: resolveEntity(void *ctx, const CHAR *publicId, const CHAR *systemId)
1.5 daniel 231: {
1.12 daniel 232: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.2 daniel 233:
234: #ifdef DEBUG_SAX
235: fprintf(stderr, "SAX.resolveEntity(%s, %s)\n", publicId, systemId);
236: #endif
1.5 daniel 237:
1.10 daniel 238: /*
239: * TODO : not 100% sure that the appropriate handling in that case.
240: */
1.12 daniel 241: if (systemId != NULL) {
1.18 daniel 242: if (!xmlStrncmp(systemId, "http://", 7)) {
243: /* !!!!!!!!! TODO */
244: } else if (!xmlStrncmp(systemId, "ftp://", 6)) {
245: /* !!!!!!!!! TODO */
246: } else {
247: return(xmlNewInputFromFile(ctxt, systemId));
248: }
1.12 daniel 249: }
1.1 daniel 250: return(NULL);
251: }
252:
1.5 daniel 253: /**
1.10 daniel 254: * getEntity:
1.16 daniel 255: * @ctx: the user data (XML parser context)
1.10 daniel 256: * @name: The entity name
257: *
258: * Get an entity by name
259: *
1.13 daniel 260: * Returns the xmlEntityPtr if found.
1.10 daniel 261: */
262: xmlEntityPtr
1.11 daniel 263: getEntity(void *ctx, const CHAR *name)
1.10 daniel 264: {
1.11 daniel 265: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 266: xmlEntityPtr ret;
267:
268: #ifdef DEBUG_SAX
269: fprintf(stderr, "SAX.getEntity(%s)\n", name);
270: #endif
271:
272: ret = xmlGetDocEntity(ctxt->myDoc, name);
273: return(ret);
274: }
275:
1.20 daniel 276: /**
277: * getParameterEntity:
278: * @ctx: the user data (XML parser context)
279: * @name: The entity name
280: *
281: * Get a parameter entity by name
282: *
283: * Returns the xmlEntityPtr if found.
284: */
285: xmlEntityPtr
286: getParameterEntity(void *ctx, const CHAR *name)
287: {
288: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
289: xmlEntityPtr ret;
290:
291: #ifdef DEBUG_SAX
292: fprintf(stderr, "SAX.getParameterEntity(%s)\n", name);
293: #endif
294:
295: ret = xmlGetParameterEntity(ctxt->myDoc, name);
296: return(ret);
297: }
298:
1.10 daniel 299:
300: /**
301: * entityDecl:
1.16 daniel 302: * @ctx: the user data (XML parser context)
1.10 daniel 303: * @name: the entity name
304: * @type: the entity type
305: * @publicId: The public ID of the entity
306: * @systemId: The system ID of the entity
307: * @content: the entity value (without processing).
308: *
309: * An entity definition has been parsed
310: */
311: void
1.11 daniel 312: entityDecl(void *ctx, const CHAR *name, int type,
1.10 daniel 313: const CHAR *publicId, const CHAR *systemId, CHAR *content)
314: {
1.11 daniel 315: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 316:
317: #ifdef DEBUG_SAX
318: fprintf(stderr, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
319: name, type, publicId, systemId, content);
320: #endif
321: xmlAddDocEntity(ctxt->myDoc, name, type, publicId, systemId, content);
322: }
323:
324: /**
325: * attributeDecl:
1.16 daniel 326: * @ctx: the user data (XML parser context)
1.10 daniel 327: * @name: the attribute name
328: * @type: the attribute type
329: * @publicId: The public ID of the attribute
330: * @systemId: The system ID of the attribute
331: * @content: the attribute value (without processing).
332: *
333: * An attribute definition has been parsed
334: */
335: void
1.11 daniel 336: attributeDecl(void *ctx, const CHAR *elem, const CHAR *name,
1.10 daniel 337: int type, int def, const CHAR *defaultValue,
338: xmlEnumerationPtr tree)
339: {
1.11 daniel 340: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.21 daniel 341: xmlAttributePtr attr;
1.10 daniel 342:
343: #ifdef DEBUG_SAX
344: fprintf(stderr, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
345: elem, name, type, def, defaultValue);
346: #endif
1.21 daniel 347: attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
348: name, type, def, defaultValue, tree);
349: if (attr == 0) ctxt->valid = 0;
1.23 daniel 350: if (ctxt->validate && ctxt->wellFormed &&
351: ctxt->myDoc && ctxt->myDoc->intSubset)
1.21 daniel 352: ctxt->valid &= xmlValidateAttributeDecl(&ctxt->vctxt, ctxt->myDoc,
353: attr);
1.10 daniel 354: }
355:
356: /**
357: * elementDecl:
1.16 daniel 358: * @ctx: the user data (XML parser context)
1.10 daniel 359: * @name: the element name
360: * @type: the element type
361: * @publicId: The public ID of the element
362: * @systemId: The system ID of the element
363: * @content: the element value (without processing).
364: *
365: * An element definition has been parsed
366: */
367: void
1.11 daniel 368: elementDecl(void *ctx, const CHAR *name, int type,
1.10 daniel 369: xmlElementContentPtr content)
370: {
1.11 daniel 371: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.21 daniel 372: xmlElementPtr elem;
1.10 daniel 373:
374: #ifdef DEBUG_SAX
375: fprintf(stderr, "SAX.elementDecl(%s, %d, ...)\n",
376: name, type);
377: #endif
1.21 daniel 378:
379: elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset,
380: name, type, content);
381: if (elem == 0) ctxt->valid = 0;
1.23 daniel 382: if (ctxt->validate && ctxt->wellFormed &&
383: ctxt->myDoc && ctxt->myDoc->intSubset)
1.21 daniel 384: ctxt->valid &= xmlValidateElementDecl(&ctxt->vctxt, ctxt->myDoc, elem);
1.10 daniel 385: }
386:
387: /**
1.5 daniel 388: * notationDecl:
1.16 daniel 389: * @ctx: the user data (XML parser context)
1.5 daniel 390: * @name: The name of the notation
391: * @publicId: The public ID of the entity
392: * @systemId: The system ID of the entity
393: *
1.1 daniel 394: * What to do when a notation declaration has been parsed.
395: * TODO Not handled currently.
396: */
1.5 daniel 397: void
1.11 daniel 398: notationDecl(void *ctx, const CHAR *name,
1.5 daniel 399: const CHAR *publicId, const CHAR *systemId)
400: {
1.11 daniel 401: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.21 daniel 402: xmlNotationPtr nota;
403:
1.2 daniel 404: #ifdef DEBUG_SAX
405: fprintf(stderr, "SAX.notationDecl(%s, %s, %s)\n", name, publicId, systemId);
406: #endif
1.21 daniel 407:
408: nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
409: publicId, systemId);
410: if (nota == 0) ctxt->valid = 0;
1.23 daniel 411: if (ctxt->validate && ctxt->wellFormed &&
412: ctxt->myDoc && ctxt->myDoc->intSubset)
1.21 daniel 413: ctxt->valid &= xmlValidateNotationDecl(&ctxt->vctxt, ctxt->myDoc,
414: nota);
1.1 daniel 415: }
416:
1.5 daniel 417: /**
418: * unparsedEntityDecl:
1.16 daniel 419: * @ctx: the user data (XML parser context)
1.5 daniel 420: * @name: The name of the entity
421: * @publicId: The public ID of the entity
422: * @systemId: The system ID of the entity
423: * @notationName: the name of the notation
424: *
1.1 daniel 425: * What to do when an unparsed entity declaration is parsed
426: * TODO Create an Entity node.
427: */
1.5 daniel 428: void
1.11 daniel 429: unparsedEntityDecl(void *ctx, const CHAR *name,
1.5 daniel 430: const CHAR *publicId, const CHAR *systemId,
431: const CHAR *notationName)
432: {
1.11 daniel 433: /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
1.2 daniel 434: #ifdef DEBUG_SAX
435: fprintf(stderr, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
436: name, publicId, systemId, notationName);
437: #endif
1.1 daniel 438: }
439:
1.5 daniel 440: /**
441: * setDocumentLocator:
1.16 daniel 442: * @ctx: the user data (XML parser context)
1.5 daniel 443: * @loc: A SAX Locator
444: *
1.1 daniel 445: * Receive the document locator at startup, actually xmlDefaultSAXLocator
446: * Everything is available on the context, so this is useless in our case.
447: */
1.5 daniel 448: void
1.11 daniel 449: setDocumentLocator(void *ctx, xmlSAXLocatorPtr loc)
1.5 daniel 450: {
1.11 daniel 451: /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
1.2 daniel 452: #ifdef DEBUG_SAX
453: fprintf(stderr, "SAX.setDocumentLocator()\n");
454: #endif
1.1 daniel 455: }
456:
1.5 daniel 457: /**
458: * startDocument:
1.16 daniel 459: * @ctx: the user data (XML parser context)
1.5 daniel 460: *
1.1 daniel 461: * called when the document start being processed.
462: */
1.5 daniel 463: void
1.11 daniel 464: startDocument(void *ctx)
1.5 daniel 465: {
1.11 daniel 466: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 467: xmlDocPtr doc;
468:
1.2 daniel 469: #ifdef DEBUG_SAX
470: fprintf(stderr, "SAX.startDocument()\n");
471: #endif
1.10 daniel 472: doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
473: if (doc != NULL) {
474: if (ctxt->encoding != NULL)
475: doc->encoding = xmlStrdup(ctxt->encoding);
476: else
477: doc->encoding = NULL;
478: doc->standalone = ctxt->standalone;
479: }
1.1 daniel 480: }
481:
1.5 daniel 482: /**
483: * endDocument:
1.16 daniel 484: * @ctx: the user data (XML parser context)
1.5 daniel 485: *
1.1 daniel 486: * called when the document end has been detected.
487: */
1.5 daniel 488: void
1.11 daniel 489: endDocument(void *ctx)
1.5 daniel 490: {
1.11 daniel 491: /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
1.2 daniel 492: #ifdef DEBUG_SAX
493: fprintf(stderr, "SAX.endDocument()\n");
494: #endif
1.1 daniel 495: }
496:
1.5 daniel 497: /**
1.10 daniel 498: * attribute:
1.16 daniel 499: * @ctx: the user data (XML parser context)
1.10 daniel 500: * @name: The attribute name
501: * @value: The attribute value
502: *
503: * Handle an attribute that has been read by the parser.
504: * The default handling is to convert the attribute into an
505: * DOM subtree and past it in a new xmlAttr element added to
506: * the element.
507: */
508: void
1.11 daniel 509: attribute(void *ctx, const CHAR *fullname, const CHAR *value)
1.10 daniel 510: {
1.11 daniel 511: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 512: xmlAttrPtr ret;
513: CHAR *name;
514: CHAR *ns;
515:
516: /****************
517: #ifdef DEBUG_SAX
518: fprintf(stderr, "SAX.attribute(%s, %s)\n", fullname, value);
519: #endif
520: ****************/
521: /*
522: * Split the full name into a namespace prefix and the tag name
523: */
524: name = xmlSplitQName(fullname, &ns);
525:
526: /*
527: * Check whether it's a namespace definition
528: */
529: if ((ns == NULL) &&
530: (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
531: (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
532: /* a default namespace definition */
533: xmlNewNs(ctxt->node, value, NULL);
534: if (name != NULL)
535: free(name);
536: return;
537: }
538: if ((ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
539: (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
540: /* a standard namespace definition */
541: xmlNewNs(ctxt->node, value, name);
542: free(ns);
543: if (name != NULL)
544: free(name);
545: return;
546: }
547:
548: ret = xmlNewProp(ctxt->node, name, NULL);
1.22 daniel 549:
1.26 daniel 550: if (ret != NULL) {
551: if (ctxt->replaceEntities == 0)
552: ret->val = xmlStringGetNodeList(ctxt->myDoc, value);
553: else
554: ret->val = xmlNewDocText(ctxt->myDoc, value);
555: }
1.22 daniel 556:
1.23 daniel 557: if (ctxt->validate && ctxt->wellFormed &&
558: ctxt->myDoc && ctxt->myDoc->intSubset)
1.22 daniel 559: ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
560: ctxt->node, ret, value);
1.26 daniel 561: else {
562: /*
563: * when validating, the ID registration is done at the attribute
564: * validation level. Otherwise we have to do specific handling here.
565: */
566: if (xmlIsID(ctxt->myDoc, ctxt->node, ret))
567: xmlAddID(&ctxt->vctxt, ctxt->myDoc, value, ret);
568: }
1.22 daniel 569:
1.10 daniel 570: if (name != NULL)
571: free(name);
572: if (ns != NULL)
573: free(ns);
574: }
575:
576: /**
1.5 daniel 577: * startElement:
1.16 daniel 578: * @ctx: the user data (XML parser context)
1.5 daniel 579: * @name: The element name
1.10 daniel 580: * @atts: An array of name/value attributes pairs, NULL terminated
1.5 daniel 581: *
1.1 daniel 582: * called when an opening tag has been processed.
583: * TODO We currently have a small pblm with the arguments ...
584: */
1.5 daniel 585: void
1.11 daniel 586: startElement(void *ctx, const CHAR *fullname, const CHAR **atts)
1.5 daniel 587: {
1.11 daniel 588: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 589: xmlNodePtr ret;
590: xmlNodePtr parent = ctxt->node;
591: xmlNsPtr ns;
592: CHAR *name;
593: CHAR *prefix;
594: const CHAR *att;
595: const CHAR *value;
596:
597: int i;
598:
1.2 daniel 599: #ifdef DEBUG_SAX
1.10 daniel 600: fprintf(stderr, "SAX.startElement(%s)\n", fullname);
1.2 daniel 601: #endif
1.10 daniel 602: /*
603: * Split the full name into a namespace prefix and the tag name
604: */
605: name = xmlSplitQName(fullname, &prefix);
606:
607:
608: /*
609: * Note : the namespace resolution is deferred until the end of the
610: * attributes parsing, since local namespace can be defined as
611: * an attribute at this level.
612: */
613: ret = xmlNewDocNode(ctxt->myDoc, NULL, name, NULL);
614: if (ret == NULL) return;
1.26 daniel 615: if (ctxt->myDoc->root == NULL) {
616: #ifdef DEBUG_SAX_TREE
617: fprintf(stderr, "Setting %s as root\n", name);
618: #endif
1.10 daniel 619: ctxt->myDoc->root = ret;
1.26 daniel 620: } else if (parent == NULL) {
621: parent = ctxt->myDoc->root;
622: }
1.10 daniel 623:
624: /*
625: * We are parsing a new node.
626: */
1.26 daniel 627: #ifdef DEBUG_SAX_TREE
628: fprintf(stderr, "pushing(%s)\n", name);
629: #endif
1.10 daniel 630: nodePush(ctxt, ret);
631:
632: /*
633: * Link the child element
634: */
1.26 daniel 635: if (parent != NULL) {
636: if (parent->type == XML_ELEMENT_NODE) {
637: #ifdef DEBUG_SAX_TREE
638: fprintf(stderr, "adding child %s to %s\n", name, parent->name);
639: #endif
640: xmlAddChild(parent, ret);
641: } else {
642: #ifdef DEBUG_SAX_TREE
643: fprintf(stderr, "adding sibling %s to ", name);
644: xmlDebugDumpOneNode(stderr, parent, 0);
645: #endif
646: xmlAddSibling(parent, ret);
647: }
648: }
1.10 daniel 649:
650: /*
651: * process all the attributes.
652: */
653: if (atts != NULL) {
654: i = 0;
655: att = atts[i++];
656: value = atts[i++];
657: while ((att != NULL) && (value != NULL)) {
658: /*
659: * Handle one pair of attribute/value
660: */
661: attribute(ctxt, att, value);
662:
663: /*
664: * Next ones
665: */
666: att = atts[i++];
667: value = atts[i++];
668: }
669: }
670:
671: /*
672: * Search the namespace, note that since the attributes have been
673: * processed, the local namespaces are available.
674: */
675: ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
676: if ((ns == NULL) && (parent != NULL))
677: ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
678: xmlSetNs(ret, ns);
679:
680: if (prefix != NULL)
681: free(prefix);
682: if (name != NULL)
683: free(name);
684:
1.1 daniel 685: }
686:
1.5 daniel 687: /**
688: * endElement:
1.16 daniel 689: * @ctx: the user data (XML parser context)
1.5 daniel 690: * @name: The element name
691: *
1.1 daniel 692: * called when the end of an element has been detected.
693: */
1.5 daniel 694: void
1.11 daniel 695: endElement(void *ctx, const CHAR *name)
1.5 daniel 696: {
1.11 daniel 697: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 698: xmlParserNodeInfo node_info;
699: xmlNodePtr cur = ctxt->node;
700:
1.2 daniel 701: #ifdef DEBUG_SAX
1.10 daniel 702: if (name == NULL)
703: fprintf(stderr, "SAX.endElement(NULL)\n");
704: else
705: fprintf(stderr, "SAX.endElement(%s)\n", name);
706: #endif
707:
708: /* Capture end position and add node */
709: if (cur != NULL && ctxt->record_info) {
710: node_info.end_pos = ctxt->input->cur - ctxt->input->base;
711: node_info.end_line = ctxt->input->line;
712: node_info.node = cur;
713: xmlParserAddNodeInfo(ctxt, &node_info);
714: }
715:
1.23 daniel 716: if (ctxt->validate && ctxt->wellFormed &&
717: ctxt->myDoc && ctxt->myDoc->intSubset)
1.22 daniel 718: ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc,
719: cur);
720:
721:
1.10 daniel 722: /*
723: * end of parsing of this node.
724: */
1.26 daniel 725: #ifdef DEBUG_SAX_TREE
726: fprintf(stderr, "popping(%s)\n", cur->name);
727: #endif
1.10 daniel 728: nodePop(ctxt);
1.1 daniel 729: }
730:
1.5 daniel 731: /**
1.10 daniel 732: * reference:
1.16 daniel 733: * @ctx: the user data (XML parser context)
1.10 daniel 734: * @name: The entity name
1.5 daniel 735: *
1.10 daniel 736: * called when an entity reference is detected.
1.5 daniel 737: */
738: void
1.11 daniel 739: reference(void *ctx, const CHAR *name)
1.5 daniel 740: {
1.11 daniel 741: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 742: xmlNodePtr ret;
743:
1.5 daniel 744: #ifdef DEBUG_SAX
1.10 daniel 745: fprintf(stderr, "SAX.reference(%s)\n", name);
1.5 daniel 746: #endif
1.10 daniel 747: ret = xmlNewReference(ctxt->myDoc, name);
1.26 daniel 748: #ifdef DEBUG_SAX_TREE
749: fprintf(stderr, "add reference %s to %s \n", name, ctxt->node->name);
750: #endif
1.10 daniel 751: xmlAddChild(ctxt->node, ret);
1.5 daniel 752: }
753:
754: /**
755: * characters:
1.16 daniel 756: * @ctx: the user data (XML parser context)
1.5 daniel 757: * @ch: a CHAR string
758: * @len: the number of CHAR
759: *
1.1 daniel 760: * receiving some chars from the parser.
761: * Question: how much at a time ???
762: */
1.5 daniel 763: void
1.11 daniel 764: characters(void *ctx, const CHAR *ch, int len)
1.5 daniel 765: {
1.11 daniel 766: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.2 daniel 767: xmlNodePtr lastChild;
768:
769: #ifdef DEBUG_SAX
1.10 daniel 770: fprintf(stderr, "SAX.characters(%.30s, %d)\n", ch, len);
1.2 daniel 771: #endif
772: /*
773: * Handle the data if any. If there is no child
774: * add it as content, otherwise if the last child is text,
775: * concatenate it, else create a new node of type text.
776: */
777:
778: lastChild = xmlGetLastChild(ctxt->node);
1.26 daniel 779: #ifdef DEBUG_SAX_TREE
780: fprintf(stderr, "add chars to %s \n", ctxt->node->name);
781: #endif
1.2 daniel 782: if (lastChild == NULL)
1.10 daniel 783: xmlNodeAddContentLen(ctxt->node, ch, len);
1.2 daniel 784: else {
785: if (xmlNodeIsText(lastChild))
1.10 daniel 786: xmlTextConcat(lastChild, ch, len);
1.2 daniel 787: else {
1.10 daniel 788: lastChild = xmlNewTextLen(ch, len);
1.2 daniel 789: xmlAddChild(ctxt->node, lastChild);
790: }
791: }
1.1 daniel 792: }
793:
1.5 daniel 794: /**
795: * ignorableWhitespace:
1.16 daniel 796: * @ctx: the user data (XML parser context)
1.5 daniel 797: * @ch: a CHAR string
798: * @len: the number of CHAR
799: *
1.1 daniel 800: * receiving some ignorable whitespaces from the parser.
801: * Question: how much at a time ???
802: */
1.5 daniel 803: void
1.11 daniel 804: ignorableWhitespace(void *ctx, const CHAR *ch, int len)
1.5 daniel 805: {
1.11 daniel 806: /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
1.2 daniel 807: #ifdef DEBUG_SAX
1.10 daniel 808: fprintf(stderr, "SAX.ignorableWhitespace(%.30s, %d)\n", ch, len);
1.2 daniel 809: #endif
1.1 daniel 810: }
811:
1.5 daniel 812: /**
813: * processingInstruction:
1.16 daniel 814: * @ctx: the user data (XML parser context)
1.5 daniel 815: * @target: the target name
816: * @data: the PI data's
817: * @len: the number of CHAR
818: *
819: * A processing instruction has been parsed.
820: */
821: void
1.11 daniel 822: processingInstruction(void *ctx, const CHAR *target,
1.5 daniel 823: const CHAR *data)
824: {
1.26 daniel 825: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
826: xmlNodePtr ret;
827: xmlNodePtr parent = ctxt->node;
828:
1.2 daniel 829: #ifdef DEBUG_SAX
830: fprintf(stderr, "SAX.processingInstruction(%s, %s)\n", target, data);
831: #endif
1.26 daniel 832:
833: ret = xmlNewPI(target, data);
834: if (ret == NULL) return;
835: ret->doc = ctxt->myDoc;
836: if (ctxt->myDoc->root == NULL) {
837: #ifdef DEBUG_SAX_TREE
838: fprintf(stderr, "Setting PI %s as root\n", target);
839: #endif
840: ctxt->myDoc->root = ret;
841: } else if (parent == NULL) {
842: parent = ctxt->myDoc->root;
843: }
844: if (parent != NULL) {
845: if (parent->type == XML_ELEMENT_NODE) {
846: #ifdef DEBUG_SAX_TREE
847: fprintf(stderr, "adding PI child %s to %s\n", target, parent->name);
848: #endif
849: xmlAddChild(parent, ret);
850: } else {
851: #ifdef DEBUG_SAX_TREE
852: fprintf(stderr, "adding PI sibling %s to ", target);
853: xmlDebugDumpOneNode(stderr, parent, 0);
854: #endif
855: xmlAddSibling(parent, ret);
856: }
857: }
858:
1.1 daniel 859: }
860:
1.10 daniel 861: /**
862: * globalNamespace:
1.16 daniel 863: * @ctx: the user data (XML parser context)
1.10 daniel 864: * @href: the namespace associated URN
865: * @prefix: the namespace prefix
866: *
867: * An old global namespace has been parsed.
868: */
869: void
1.11 daniel 870: globalNamespace(void *ctx, const CHAR *href, const CHAR *prefix)
1.10 daniel 871: {
1.11 daniel 872: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 873: #ifdef DEBUG_SAX
874: fprintf(stderr, "SAX.globalNamespace(%s, %s)\n", href, prefix);
875: #endif
876: xmlNewGlobalNs(ctxt->myDoc, href, prefix);
877: }
878:
879: /**
880: * setNamespace:
1.16 daniel 881: * @ctx: the user data (XML parser context)
1.10 daniel 882: * @name: the namespace prefix
883: *
884: * Set the current element namespace.
885: */
886: void
1.11 daniel 887: setNamespace(void *ctx, const CHAR *name)
1.10 daniel 888: {
1.11 daniel 889: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 890: xmlNsPtr ns;
891: xmlNodePtr parent;
892:
893: #ifdef DEBUG_SAX
894: fprintf(stderr, "SAX.setNamespace(%s)\n", name);
895: #endif
896: ns = xmlSearchNs(ctxt->myDoc, ctxt->node, name);
897: if (ns == NULL) { /* ctxt->node may not have a parent yet ! */
898: if (ctxt->nodeNr >= 2) {
899: parent = ctxt->nodeTab[ctxt->nodeNr - 2];
900: if (parent != NULL)
901: ns = xmlSearchNs(ctxt->myDoc, parent, name);
902: }
903: }
904: xmlSetNs(ctxt->node, ns);
905: }
906:
907: /**
908: * getNamespace:
1.16 daniel 909: * @ctx: the user data (XML parser context)
1.10 daniel 910: *
911: * Get the current element namespace.
912: */
913: xmlNsPtr
1.11 daniel 914: getNamespace(void *ctx)
1.10 daniel 915: {
1.11 daniel 916: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 917: xmlNsPtr ret;
918:
919: #ifdef DEBUG_SAX
920: fprintf(stderr, "SAX.getNamespace()\n");
921: #endif
922: ret = ctxt->node->ns;
923: return(ret);
924: }
925:
926: /**
927: * checkNamespace:
1.16 daniel 928: * @ctx: the user data (XML parser context)
1.10 daniel 929: * @namespace: the namespace to check against
930: *
931: * Check that the current element namespace is the same as the
932: * one read upon parsing.
933: */
934: int
1.11 daniel 935: checkNamespace(void *ctx, CHAR *namespace)
1.10 daniel 936: {
1.11 daniel 937: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 938: xmlNodePtr cur = ctxt->node;
939:
940: #ifdef DEBUG_SAX
941: fprintf(stderr, "SAX.checkNamespace(%s)\n", namespace);
942: #endif
943:
944: /*
945: * Check that the Name in the ETag is the same as in the STag.
946: */
947: if (namespace == NULL) {
948: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
949: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
950: ctxt->sax->error(ctxt,
951: "End tags for %s don't hold the namespace %s\n",
952: cur->name, cur->ns->prefix);
953: ctxt->wellFormed = 0;
954: }
955: } else {
956: if ((cur->ns == NULL) || (cur->ns->prefix == NULL)) {
957: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
958: ctxt->sax->error(ctxt,
959: "End tags %s holds a prefix %s not used by the open tag\n",
960: cur->name, namespace);
961: ctxt->wellFormed = 0;
962: } else if (strcmp(namespace, cur->ns->prefix)) {
963: if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
964: ctxt->sax->error(ctxt,
965: "Start and End tags for %s don't use the same namespaces: %s and %s\n",
966: cur->name, cur->ns->prefix, namespace);
967: ctxt->wellFormed = 0;
968: } else
969: return(1);
970: }
971: return(0);
972: }
973:
974: /**
975: * namespaceDecl:
1.16 daniel 976: * @ctx: the user data (XML parser context)
1.10 daniel 977: * @href: the namespace associated URN
978: * @prefix: the namespace prefix
979: *
980: * A namespace has been parsed.
981: */
982: void
1.11 daniel 983: namespaceDecl(void *ctx, const CHAR *href, const CHAR *prefix)
1.10 daniel 984: {
1.11 daniel 985: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.10 daniel 986: #ifdef DEBUG_SAX
987: if (prefix == NULL)
988: fprintf(stderr, "SAX.namespaceDecl(%s, NULL)\n", href);
989: else
990: fprintf(stderr, "SAX.namespaceDecl(%s, %s)\n", href, prefix);
991: #endif
992: xmlNewNs(ctxt->node, href, prefix);
993: }
994:
995: /**
996: * comment:
1.16 daniel 997: * @ctx: the user data (XML parser context)
1.10 daniel 998: * @value: the comment content
999: *
1000: * A comment has been parsed.
1001: */
1002: void
1.11 daniel 1003: comment(void *ctx, const CHAR *value)
1.10 daniel 1004: {
1.11 daniel 1005: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1.17 daniel 1006: xmlNodePtr ret;
1.27 ! daniel 1007: xmlNodePtr parent = ctxt->node;
1.17 daniel 1008:
1.10 daniel 1009: #ifdef DEBUG_SAX
1010: fprintf(stderr, "SAX.comment(%s)\n", value);
1011: #endif
1.17 daniel 1012: ret = xmlNewDocComment(ctxt->myDoc, value);
1.27 ! daniel 1013: if (ret == NULL) return;
! 1014:
! 1015: if (ctxt->myDoc->root == NULL) {
! 1016: #ifdef DEBUG_SAX_TREE
! 1017: fprintf(stderr, "Setting comment as root\n");
! 1018: #endif
! 1019: ctxt->myDoc->root = ret;
! 1020: } else if (parent == NULL) {
! 1021: parent = ctxt->myDoc->root;
! 1022: }
! 1023: if (parent != NULL) {
! 1024: if (parent->type == XML_ELEMENT_NODE) {
! 1025: #ifdef DEBUG_SAX_TREE
! 1026: fprintf(stderr, "adding comment child to %s\n", parent->name);
! 1027: #endif
! 1028: xmlAddChild(parent, ret);
! 1029: } else {
! 1030: #ifdef DEBUG_SAX_TREE
! 1031: fprintf(stderr, "adding comment sibling to ");
! 1032: xmlDebugDumpOneNode(stderr, parent, 0);
! 1033: #endif
! 1034: xmlAddSibling(parent, ret);
! 1035: }
! 1036: }
1.25 daniel 1037: }
1038:
1039: /**
1040: * cdataBlock:
1041: * @ctx: the user data (XML parser context)
1042: * @value: The pcdata content
1043: * @len: the block length
1044: *
1045: * called when a pcdata block has been parsed
1046: */
1047: void
1048: cdataBlock(void *ctx, const CHAR *value, int len)
1049: {
1050: xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
1051: xmlNodePtr ret;
1052:
1053: #ifdef DEBUG_SAX
1.26 daniel 1054: fprintf(stderr, "SAX.pcdata(%.10s, %d)\n", value, len);
1.25 daniel 1055: #endif
1056: ret = xmlNewCDataBlock(ctxt->myDoc, value, len);
1057: xmlAddChild(ctxt->node, ret);
1058: /* !!!!! merges */
1.10 daniel 1059: }
1060:
1.18 daniel 1061: /*
1062: * Default handler for XML, builds the DOM tree
1063: */
1.1 daniel 1064: xmlSAXHandler xmlDefaultSAXHandler = {
1.10 daniel 1065: internalSubset,
1066: isStandalone,
1067: hasInternalSubset,
1068: hasExternalSubset,
1.1 daniel 1069: resolveEntity,
1.10 daniel 1070: getEntity,
1071: entityDecl,
1.1 daniel 1072: notationDecl,
1.10 daniel 1073: attributeDecl,
1074: elementDecl,
1.1 daniel 1075: unparsedEntityDecl,
1076: setDocumentLocator,
1077: startDocument,
1078: endDocument,
1079: startElement,
1080: endElement,
1.10 daniel 1081: reference,
1.1 daniel 1082: characters,
1083: ignorableWhitespace,
1084: processingInstruction,
1.10 daniel 1085: comment,
1.1 daniel 1086: xmlParserWarning,
1087: xmlParserError,
1.2 daniel 1088: xmlParserError,
1.20 daniel 1089: getParameterEntity,
1.25 daniel 1090: cdataBlock,
1.1 daniel 1091: };
1.2 daniel 1092:
1.5 daniel 1093: /**
1094: * xmlDefaultSAXHandlerInit:
1095: *
1096: * Initialize the default SAX handler
1097: */
1098: void
1099: xmlDefaultSAXHandlerInit(void)
1100: {
1.10 daniel 1101: xmlDefaultSAXHandler.internalSubset = internalSubset;
1102: xmlDefaultSAXHandler.isStandalone = isStandalone;
1103: xmlDefaultSAXHandler.hasInternalSubset = hasInternalSubset;
1104: xmlDefaultSAXHandler.hasExternalSubset = hasExternalSubset;
1.2 daniel 1105: xmlDefaultSAXHandler.resolveEntity = resolveEntity;
1.10 daniel 1106: xmlDefaultSAXHandler.getEntity = getEntity;
1.20 daniel 1107: xmlDefaultSAXHandler.getParameterEntity = getParameterEntity;
1.10 daniel 1108: xmlDefaultSAXHandler.entityDecl = entityDecl;
1109: xmlDefaultSAXHandler.attributeDecl = attributeDecl;
1110: xmlDefaultSAXHandler.elementDecl = elementDecl;
1.2 daniel 1111: xmlDefaultSAXHandler.notationDecl = notationDecl;
1112: xmlDefaultSAXHandler.unparsedEntityDecl = unparsedEntityDecl;
1113: xmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
1114: xmlDefaultSAXHandler.startDocument = startDocument;
1115: xmlDefaultSAXHandler.endDocument = endDocument;
1116: xmlDefaultSAXHandler.startElement = startElement;
1117: xmlDefaultSAXHandler.endElement = endElement;
1.10 daniel 1118: xmlDefaultSAXHandler.reference = reference;
1.2 daniel 1119: xmlDefaultSAXHandler.characters = characters;
1.25 daniel 1120: xmlDefaultSAXHandler.cdataBlock = cdataBlock;
1.2 daniel 1121: xmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
1122: xmlDefaultSAXHandler.processingInstruction = processingInstruction;
1.10 daniel 1123: xmlDefaultSAXHandler.comment = comment;
1.2 daniel 1124: xmlDefaultSAXHandler.warning = xmlParserWarning;
1125: xmlDefaultSAXHandler.error = xmlParserError;
1126: xmlDefaultSAXHandler.fatalError = xmlParserError;
1.18 daniel 1127: }
1128:
1129: /*
1130: * Default handler for HTML, builds the DOM tree
1131: */
1132: xmlSAXHandler htmlDefaultSAXHandler = {
1133: NULL,
1134: NULL,
1135: NULL,
1136: NULL,
1137: NULL,
1138: getEntity,
1139: NULL,
1140: NULL,
1141: NULL,
1142: NULL,
1143: NULL,
1144: setDocumentLocator,
1145: startDocument,
1146: endDocument,
1147: startElement,
1148: endElement,
1149: NULL,
1150: characters,
1151: ignorableWhitespace,
1152: NULL,
1153: comment,
1154: xmlParserWarning,
1155: xmlParserError,
1156: xmlParserError,
1.20 daniel 1157: getParameterEntity,
1.25 daniel 1158: NULL,
1.18 daniel 1159: };
1160:
1161: /**
1162: * htmlDefaultSAXHandlerInit:
1163: *
1164: * Initialize the default SAX handler
1165: */
1166: void
1167: htmlDefaultSAXHandlerInit(void)
1168: {
1169: htmlDefaultSAXHandler.internalSubset = NULL;
1170: htmlDefaultSAXHandler.isStandalone = NULL;
1171: htmlDefaultSAXHandler.hasInternalSubset = NULL;
1172: htmlDefaultSAXHandler.hasExternalSubset = NULL;
1173: htmlDefaultSAXHandler.resolveEntity = NULL;
1174: htmlDefaultSAXHandler.getEntity = getEntity;
1.20 daniel 1175: htmlDefaultSAXHandler.getParameterEntity = NULL;
1.18 daniel 1176: htmlDefaultSAXHandler.entityDecl = NULL;
1177: htmlDefaultSAXHandler.attributeDecl = NULL;
1178: htmlDefaultSAXHandler.elementDecl = NULL;
1179: htmlDefaultSAXHandler.notationDecl = NULL;
1180: htmlDefaultSAXHandler.unparsedEntityDecl = NULL;
1181: htmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
1182: htmlDefaultSAXHandler.startDocument = startDocument;
1183: htmlDefaultSAXHandler.endDocument = endDocument;
1184: htmlDefaultSAXHandler.startElement = startElement;
1185: htmlDefaultSAXHandler.endElement = endElement;
1186: htmlDefaultSAXHandler.reference = NULL;
1187: htmlDefaultSAXHandler.characters = characters;
1.25 daniel 1188: htmlDefaultSAXHandler.cdataBlock = NULL;
1.18 daniel 1189: htmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
1190: htmlDefaultSAXHandler.processingInstruction = NULL;
1191: htmlDefaultSAXHandler.comment = comment;
1192: htmlDefaultSAXHandler.warning = xmlParserWarning;
1193: htmlDefaultSAXHandler.error = xmlParserError;
1194: htmlDefaultSAXHandler.fatalError = xmlParserError;
1.2 daniel 1195: }
Webmaster