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