blob: 0b6b13a9222a237d2f8717e1b8ecee733a7154d0 [file] [log] [blame]
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001/*
2 * xmlreader.c: implements the xmlTextReader streaming node API
3 *
4 * See Copyright for the status of this software.
5 *
6 * daniel@veillard.com
7 */
8
9#define IN_LIBXML
10#include "libxml.h"
11
12#include <string.h> /* for memset() only ! */
13
14#ifdef HAVE_CTYPE_H
15#include <ctype.h>
16#endif
17#ifdef HAVE_STDLIB_H
18#include <stdlib.h>
19#endif
20
21#include <libxml/xmlmemory.h>
22#include <libxml/xmlIO.h>
23#include <libxml/xmlreader.h>
24
25/* #define DEBUG_CALLBACKS */
26/* #define DEBUG_READER */
27
28/**
29 * TODO:
30 *
31 * macro to flag unimplemented blocks
32 */
33#define TODO \
34 xmlGenericError(xmlGenericErrorContext, \
35 "Unimplemented block at %s:%d\n", \
36 __FILE__, __LINE__);
37
38#ifdef DEBUG_READER
39#define DUMP_READER xmlTextReaderDebug(reader);
40#else
41#define DUMP_READER
42#endif
43
44/************************************************************************
45 * *
46 * The parser: maps the Text Reader API on top of the existing *
47 * parsing routines building a tree *
48 * *
49 ************************************************************************/
50
51#define XML_TEXTREADER_INPUT 1
52#define XML_TEXTREADER_CTXT 2
53
54typedef enum {
55 XML_TEXTREADER_MODE_NORMAL = 0,
Daniel Veillard0eb38c72002-12-14 23:00:35 +000056 XML_TEXTREADER_MODE_EOF = 1,
57 XML_TEXTREADER_MODE_CLOSED = 1
Daniel Veillarde1ca5032002-12-09 14:13:43 +000058} xmlTextReaderMode;
59
60typedef enum {
61 XML_TEXTREADER_NONE = -1,
62 XML_TEXTREADER_START= 0,
63 XML_TEXTREADER_ELEMENT= 1,
64 XML_TEXTREADER_END= 2,
65 XML_TEXTREADER_EMPTY= 3,
66 XML_TEXTREADER_BACKTRACK= 4
67} xmlTextReaderState;
68
69struct _xmlTextReader {
70 int mode; /* the parsing mode */
71 int allocs; /* what structure were deallocated */
72 xmlTextReaderState state;
73 xmlParserCtxtPtr ctxt; /* the parser context */
74 xmlSAXHandlerPtr sax; /* the parser SAX callbacks */
75 xmlParserInputBufferPtr input; /* the input */
76 startElementSAXFunc startElement;/* initial SAX callbacks */
77 endElementSAXFunc endElement; /* idem */
78 unsigned int base; /* base of the segment in the input */
79 unsigned int cur; /* current position in the input */
80 xmlNodePtr node; /* current node */
81 int depth; /* depth of the current node */
82};
83
84#ifdef DEBUG_READER
85static void
86xmlTextReaderDebug(xmlTextReaderPtr reader) {
87 if ((reader == NULL) || (reader->ctxt == NULL)) {
88 fprintf(stderr, "xmlTextReader NULL\n");
89 return;
90 }
91 fprintf(stderr, "xmlTextReader: state %d depth %d ",
92 reader->state, reader->depth);
93 if (reader->node == NULL) {
94 fprintf(stderr, "node = NULL\n");
95 } else {
96 fprintf(stderr, "node %s\n", reader->node->name);
97 }
98 fprintf(stderr, " input: base %d, cur %d, depth %d: ",
99 reader->base, reader->cur, reader->ctxt->nodeNr);
100 if (reader->input->buffer == NULL) {
101 fprintf(stderr, "buffer is NULL\n");
102 } else {
103#ifdef LIBXML_DEBUG_ENABLED
104 xmlDebugDumpString(stderr,
105 &reader->input->buffer->content[reader->cur]);
106#endif
107 fprintf(stderr, "\n");
108 }
109}
110#endif
111
112/**
113 * xmlTextReaderStartElement:
114 * @ctx: the user data (XML parser context)
115 * @fullname: The element name, including namespace prefix
116 * @atts: An array of name/value attributes pairs, NULL terminated
117 *
118 * called when an opening tag has been processed.
119 */
120static void
121xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
122 const xmlChar **atts) {
123 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
124 xmlTextReaderPtr reader = ctxt->_private;
125
126#ifdef DEBUG_CALLBACKS
127 printf("xmlTextReaderStartElement(%s)\n", fullname);
128#endif
129 if ((reader != NULL) && (reader->startElement != NULL))
130 reader->startElement(ctx, fullname, atts);
131 reader->state = XML_TEXTREADER_ELEMENT;
132}
133
134/**
135 * xmlTextReaderEndElement:
136 * @ctx: the user data (XML parser context)
137 * @fullname: The element name, including namespace prefix
138 *
139 * called when an ending tag has been processed.
140 */
141static void
142xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
143 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
144 xmlTextReaderPtr reader = ctxt->_private;
145
146#ifdef DEBUG_CALLBACKS
147 printf("xmlTextReaderEndElement(%s)\n", fullname);
148#endif
149 if ((reader != NULL) && (reader->endElement != NULL))
150 reader->endElement(ctx, fullname);
151 if (reader->state == XML_TEXTREADER_ELEMENT)
152 reader->state = XML_TEXTREADER_EMPTY;
153 else
154 reader->state = XML_TEXTREADER_END;
155}
156
157/**
158 * xmlTextReaderPushData:
159 * @reader: the xmlTextReaderPtr used
160 *
161 * Push data down the progressive parser until a significant callback
162 * got raised.
163 *
164 * Returns -1 in case of failure, 0 otherwise
165 */
166static int
167xmlTextReaderPushData(xmlTextReaderPtr reader) {
168 unsigned int cur = reader->cur;
169 xmlBufferPtr inbuf;
170 int val;
171
172 if ((reader->input == NULL) || (reader->input->buffer == NULL))
173 return(-1);
174
175 reader->state = XML_TEXTREADER_NONE;
176 inbuf = reader->input->buffer;
177 while (reader->state == XML_TEXTREADER_NONE) {
178 if (cur >= inbuf->use) {
179 /*
180 * Refill the buffer unless we are at the end of the stream
181 */
182 if (reader->mode != XML_TEXTREADER_MODE_EOF) {
183 val = xmlParserInputBufferRead(reader->input, 4096);
184 if (val <= 0) {
185 reader->mode = XML_TEXTREADER_MODE_EOF;
186 return(val);
187 }
188 } else
189 break;
190 }
191 if ((inbuf->content[cur] == '>') || (inbuf->content[cur] == '&')) {
192 cur = cur + 1;
193 val = xmlParseChunk(reader->ctxt,
194 (const char *) &inbuf->content[reader->cur],
195 cur - reader->cur, 0);
196 if (val != 0)
197 return(-1);
198 reader->cur = cur;
199 break;
200 } else {
201 cur = cur + 1;
202
203 /*
204 * One may have to force a flush at some point when parsing really
205 * large CDATA sections
206 */
207 if ((cur - reader->cur > 4096) && (reader->base == 0) &&
208 (reader->mode == XML_TEXTREADER_MODE_NORMAL)) {
209 cur = cur + 1;
210 val = xmlParseChunk(reader->ctxt,
211 (const char *) &inbuf->content[reader->cur],
212 cur - reader->cur, 0);
213 if (val != 0)
214 return(-1);
215 reader->cur = cur;
216 }
217 }
218 }
219 /*
220 * Discard the consumed input when needed and possible
221 */
222 if (reader->mode == XML_TEXTREADER_MODE_NORMAL) {
223 if ((reader->cur >= 4096) && (reader->base == 0)) {
224 val = xmlBufferShrink(inbuf, cur);
225 if (val >= 0) {
226 reader->cur -= val;
227 }
228 }
229 }
230
231 /*
232 * At the end of the stream signal that the work is done to the Push
233 * parser.
234 */
235 if ((reader->mode == XML_TEXTREADER_MODE_EOF) && (cur >= inbuf->use)) {
236 val = xmlParseChunk(reader->ctxt,
237 (const char *) &inbuf->content[reader->cur], 0, 1);
238 }
239 return(0);
240}
241
242/**
243 * xmlTextReaderRead:
244 * @reader: the xmlTextReaderPtr used
245 *
246 * Moves the position of the current instance to the next node in
247 * the stream, exposing its properties.
248 *
249 * Returns 1 if the node was read successfully, 0 if there is no more
250 * nodes to read, or -1 in case of error
251 */
252int
253xmlTextReaderRead(xmlTextReaderPtr reader) {
254 int val, olddepth;
255 xmlTextReaderState oldstate;
256 xmlNodePtr oldnode;
257
258 if ((reader == NULL) || (reader->ctxt == NULL))
259 return(-1);
260 if (reader->ctxt->wellFormed != 1)
261 return(-1);
262
263#ifdef DEBUG_READER
264 fprintf(stderr, "\nREAD ");
265 DUMP_READER
266#endif
267 if (reader->node == NULL) {
268 /*
269 * Initial state
270 */
271 do {
272 val = xmlTextReaderPushData(reader);
273 if (val < 0)
274 return(-1);
275 } while ((reader->ctxt->node == NULL) &&
276 (reader->mode != XML_TEXTREADER_MODE_EOF));
277 if (reader->ctxt->node == NULL) {
278 if (reader->ctxt->myDoc != NULL)
279 reader->node = reader->ctxt->myDoc->children;
280 if (reader->node == NULL)
281 return(-1);
282 } else {
283 reader->node = reader->ctxt->node;
284 }
285 reader->depth = 1;
286 return(1);
287 }
288 oldstate = reader->state;
289 olddepth = reader->ctxt->nodeNr;
290 oldnode = reader->node;
291 /*
292 * If we are not backtracking on ancestors or examined nodes,
293 * that the parser didn't finished or that we arent at the end
294 * of stream, continue processing.
295 */
296 if (oldstate != XML_TEXTREADER_BACKTRACK) {
297 while (((reader->node->children == NULL) ||
298 (reader->node->type == XML_ENTITY_REF_NODE) ||
299 (reader->node->type == XML_DTD_NODE)) &&
300 (reader->node->next == NULL) &&
301 (reader->ctxt->nodeNr == olddepth) &&
302 (reader->ctxt->instate != XML_PARSER_EOF)) {
303 val = xmlTextReaderPushData(reader);
304 if (val < 0)
305 return(-1);
306 if (reader->node == NULL)
307 return(0);
308 }
309 if ((reader->node->children != NULL) &&
310 (reader->node->type != XML_ENTITY_REF_NODE) &&
311 (reader->node->type != XML_DTD_NODE)) {
312 reader->node = reader->node->children;
313 reader->depth++;
314 if ((reader->state != XML_TEXTREADER_ELEMENT) &&
315 (reader->state != XML_TEXTREADER_EMPTY))
316 reader->state = XML_TEXTREADER_ELEMENT;
317 DUMP_READER
318 return(1);
319 }
320 }
321 if (reader->node->next != NULL) {
322 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
323 (reader->node->type == XML_ELEMENT_NODE)) {
324 reader->state = XML_TEXTREADER_END;
325 DUMP_READER
326 return(1);
327 }
328 reader->node = reader->node->next;
329 reader->state = XML_TEXTREADER_ELEMENT;
330 DUMP_READER
331 /*
332 * Cleanup of the old node
333 */
334 if (oldnode->type != XML_DTD_NODE) {
335 xmlUnlinkNode(oldnode);
336 xmlFreeNode(oldnode);
337 }
338
339 return(1);
340 }
341 reader->node = reader->node->parent;
342 if ((reader->node == NULL) ||
343 (reader->node->type == XML_DOCUMENT_NODE) ||
344#ifdef LIBXML_DOCB_ENABLED
345 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
346#endif
347 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
348 reader->node = NULL;
349 reader->depth = 0;
350
351 /*
352 * Cleanup of the old node
353 */
354 if (oldnode->type != XML_DTD_NODE) {
355 xmlUnlinkNode(oldnode);
356 xmlFreeNode(oldnode);
357 }
358
359 return(0);
360 }
361 reader->depth--;
362 reader->state = XML_TEXTREADER_BACKTRACK;
363 DUMP_READER
364 return(1);
365}
366
367/************************************************************************
368 * *
369 * Constructor and destructors *
370 * *
371 ************************************************************************/
372/**
373 * xmlNewTextReader:
374 * @input: the xmlParserInputBufferPtr used to read data
375 *
376 * Create an xmlTextReader structure fed with @input
377 *
378 * Returns the new xmlTextReaderPtr or NULL in case of error
379 */
380xmlTextReaderPtr
381xmlNewTextReader(xmlParserInputBufferPtr input) {
382 xmlTextReaderPtr ret;
383 int val;
384
385 if (input == NULL)
386 return(NULL);
387 ret = xmlMalloc(sizeof(xmlTextReader));
388 if (ret == NULL) {
389 xmlGenericError(xmlGenericErrorContext,
390 "xmlNewTextReader : malloc failed\n");
391 return(NULL);
392 }
393 memset(ret, 0, sizeof(xmlTextReader));
394 ret->input = input;
395 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
396 if (ret->sax == NULL) {
397 xmlFree(ret);
398 xmlGenericError(xmlGenericErrorContext,
399 "xmlNewTextReader : malloc failed\n");
400 return(NULL);
401 }
402 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
403 ret->startElement = ret->sax->startElement;
404 ret->sax->startElement = xmlTextReaderStartElement;
405 ret->endElement = ret->sax->endElement;
406 ret->sax->endElement = xmlTextReaderEndElement;
407
408 ret->mode = XML_TEXTREADER_MODE_NORMAL;
409 ret->node = NULL;
410 val = xmlParserInputBufferRead(input, 4);
411 if (val >= 4) {
412 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
413 (const char *) ret->input->buffer->content, 4, NULL);
414 ret->base = 0;
415 ret->cur = 4;
416 } else {
417 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, NULL);
418 ret->base = 0;
419 ret->cur = 0;
420 }
421 ret->ctxt->_private = ret;
422 ret->allocs = XML_TEXTREADER_CTXT;
423 return(ret);
424
425}
426
427/**
428 * xmlNewTextReaderFilename:
429 * @URI: the URI of the resource to process
430 *
431 * Create an xmlTextReader structure fed with the resource at @URI
432 *
433 * Returns the new xmlTextReaderPtr or NULL in case of error
434 */
435xmlTextReaderPtr
436xmlNewTextReaderFilename(const char *URI) {
437 xmlParserInputBufferPtr input;
438 xmlTextReaderPtr ret;
439
440 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
441 if (input == NULL)
442 return(NULL);
443 ret = xmlNewTextReader(input);
444 if (ret == NULL) {
445 xmlFreeParserInputBuffer(input);
446 return(NULL);
447 }
448 ret->allocs |= XML_TEXTREADER_INPUT;
449 return(ret);
450}
451
452/**
453 * xmlFreeTextReader:
454 * @reader: the xmlTextReaderPtr
455 *
456 * Deallocate all the resources associated to the reader
457 */
458void
459xmlFreeTextReader(xmlTextReaderPtr reader) {
460 if (reader == NULL)
461 return;
462 if (reader->ctxt != NULL) {
463 if (reader->ctxt->myDoc != NULL) {
464 xmlFreeDoc(reader->ctxt->myDoc);
465 reader->ctxt->myDoc = NULL;
466 }
467 if (reader->allocs & XML_TEXTREADER_CTXT)
468 xmlFreeParserCtxt(reader->ctxt);
469 }
470 if (reader->sax != NULL)
471 xmlFree(reader->sax);
472 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
473 xmlFreeParserInputBuffer(reader->input);
474 xmlFree(reader);
475}
476
477/************************************************************************
478 * *
Daniel Veillard0eb38c72002-12-14 23:00:35 +0000479 * Methods for XmlTextReader *
480 * *
481 ************************************************************************/
482/**
483 * xmlTextReaderClose:
484 * @reader: the xmlTextReaderPtr used
485 *
486 * This method releases any resources allocated by the current instance
487 * changes the state to Closed and close any underlying input.
488 *
489 * Returns 0 or -1 in case of error
490 */
491int
492xmlTextReaderClose(xmlTextReaderPtr reader) {
493 if (reader == NULL)
494 return(-1);
495 reader->node = NULL;
496 reader->mode = XML_TEXTREADER_MODE_CLOSED;
497 if (reader->ctxt != NULL) {
498 if (reader->ctxt->myDoc != NULL) {
499 xmlFreeDoc(reader->ctxt->myDoc);
500 reader->ctxt->myDoc = NULL;
501 }
502 if (reader->allocs & XML_TEXTREADER_CTXT) {
503 xmlFreeParserCtxt(reader->ctxt);
504 reader->allocs -= XML_TEXTREADER_CTXT;
505 }
506 }
507 if (reader->sax != NULL) {
508 xmlFree(reader->sax);
509 reader->sax = NULL;
510 }
511 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) {
512 xmlFreeParserInputBuffer(reader->input);
513 reader->allocs -= XML_TEXTREADER_INPUT;
514 }
515 return(0);
516}
517
518/**
519 * xmlTextReaderGetAttributeNo:
520 * @reader: the xmlTextReaderPtr used
521 * @no: the zero-based index of the attribute relative to the containing element
522 *
523 * Provides the value of the attribute with the specified index relative
524 * to the containing element.
525 *
526 * Returns a string containing the value of the specified attribute, or NULL
527 * in case of error. The string must be deallocated by the caller.
528 */
529xmlChar *
530xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
531 xmlChar *ret;
532 int i;
533 xmlAttrPtr cur;
534 xmlNsPtr ns;
535
536 if (reader == NULL)
537 return(NULL);
538 if (reader->node == NULL)
539 return(NULL);
540 /* TODO: handle the xmlDecl */
541 if (reader->node->type != XML_ELEMENT_NODE)
542 return(NULL);
543
544 ns = reader->node->nsDef;
545 for (i = 0;(i < no) && (ns != NULL);i++) {
546 ns = ns->next;
547 }
548 if (ns != NULL)
549 return(xmlStrdup(ns->href));
550
551 cur = reader->node->properties;
552 if (cur == NULL)
553 return(NULL);
554 for (;i < no;i++) {
555 cur = cur->next;
556 if (cur == NULL)
557 return(NULL);
558 }
559 /* TODO walk the DTD if present */
560
561 ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
562 if (ret == NULL) return(xmlStrdup((xmlChar *)""));
563 return(ret);
564}
565
566/**
567 * xmlTextReaderGetAttribute:
568 * @reader: the xmlTextReaderPtr used
569 * @name: the qualified name of the attribute.
570 *
571 * Provides the value of the attribute with the specified qualified name.
572 *
573 * Returns a string containing the value of the specified attribute, or NULL
574 * in case of error. The string must be deallocated by the caller.
575 */
576xmlChar *
577xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
578 xmlChar *prefix = NULL;
579 xmlChar *localname;
580 xmlNsPtr ns;
581 xmlChar *ret = NULL;
582
583 if ((reader == NULL) || (name == NULL))
584 return(NULL);
585 if (reader->node == NULL)
586 return(NULL);
587
588 /* TODO: handle the xmlDecl */
589 if (reader->node->type != XML_ELEMENT_NODE)
590 return(NULL);
591
592 localname = xmlSplitQName2(name, &prefix);
593 if (localname == NULL)
594 return(xmlGetProp(reader->node, name));
595
596 ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
597 if (ns != NULL)
598 ret = xmlGetNsProp(reader->node, localname, ns->href);
599
600 if (localname != NULL)
601 xmlFree(localname);
602 if (prefix != NULL)
603 xmlFree(prefix);
604 return(ret);
605}
606
607
608/**
609 * xmlTextReaderGetAttributeNs:
610 * @reader: the xmlTextReaderPtr used
611 * @localName: the local name of the attribute.
612 * @namespaceURI: the namespace URI of the attribute.
613 *
614 * Provides the value of the specified attribute
615 *
616 * Returns a string containing the value of the specified attribute, or NULL
617 * in case of error. The string must be deallocated by the caller.
618 */
619xmlChar *
620xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
621 const xmlChar *namespaceURI) {
622 if ((reader == NULL) || (localName == NULL))
623 return(NULL);
624 if (reader->node == NULL)
625 return(NULL);
626
627 /* TODO: handle the xmlDecl */
628 if (reader->node->type != XML_ELEMENT_NODE)
629 return(NULL);
630
631 return(xmlGetNsProp(reader->node, localName, namespaceURI));
632}
633
634/************************************************************************
635 * *
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000636 * Acces API to the current node *
637 * *
638 ************************************************************************/
639/**
640 * xmlTextReaderAttributeCount:
641 * @reader: the xmlTextReaderPtr used
642 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000643 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000644 *
645 * Returns 0 i no attributes, -1 in case of error or the attribute count
646 */
647int
648xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
649 int ret;
650 xmlAttrPtr attr;
651
652 if (reader == NULL)
653 return(-1);
654 if (reader->node == NULL)
655 return(0);
656 if (reader->node->type != XML_ELEMENT_NODE)
657 return(0);
658 if ((reader->state == XML_TEXTREADER_END) ||
659 (reader->state == XML_TEXTREADER_BACKTRACK))
660 return(0);
661 ret = 0;
662 attr = reader->node->properties;
663 while (attr != NULL) {
664 ret++;
665 attr = attr->next;
666 }
667 return(ret);
668}
669
670/**
671 * xmlTextReaderNodeType:
672 * @reader: the xmlTextReaderPtr used
673 *
674 * Get the node type of the current node
675 * Reference:
676 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
677 *
678 * Returns the xmlNodeType of the current node or -1 in case of error
679 */
680int
681xmlTextReaderNodeType(xmlTextReaderPtr reader) {
682 if (reader == NULL)
683 return(-1);
684 if (reader->node == NULL)
685 return(0);
686 switch (reader->node->type) {
687 case XML_ELEMENT_NODE:
688 if ((reader->state == XML_TEXTREADER_END) ||
689 (reader->state == XML_TEXTREADER_BACKTRACK))
690 return(15);
691 return(1);
692 case XML_ATTRIBUTE_NODE:
693 return(2);
694 case XML_TEXT_NODE:
695 return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
696 case XML_CDATA_SECTION_NODE:
697 return(4);
698 case XML_ENTITY_REF_NODE:
699 return(5);
700 case XML_ENTITY_NODE:
701 return(6);
702 case XML_PI_NODE:
703 return(7);
704 case XML_COMMENT_NODE:
705 return(8);
706 case XML_DOCUMENT_NODE:
707 case XML_HTML_DOCUMENT_NODE:
708#ifdef LIBXML_DOCB_ENABLED
709 case XML_DOCB_DOCUMENT_NODE:
710#endif
711 return(9);
712 case XML_DOCUMENT_FRAG_NODE:
713 return(11);
714 case XML_NOTATION_NODE:
715 return(12);
716 case XML_DOCUMENT_TYPE_NODE:
717 case XML_DTD_NODE:
718 return(10);
719
720 case XML_ELEMENT_DECL:
721 case XML_ATTRIBUTE_DECL:
722 case XML_ENTITY_DECL:
723 case XML_NAMESPACE_DECL:
724 case XML_XINCLUDE_START:
725 case XML_XINCLUDE_END:
726 return(0);
727 }
728 return(-1);
729}
730
731/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000732 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000733 * @reader: the xmlTextReaderPtr used
734 *
735 * Check if the current node is empty
736 *
737 * Returns 1 if empty, 0 if not and -1 in case of error
738 */
739int
740xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
741 if ((reader == NULL) || (reader->node == NULL))
742 return(-1);
743 if (reader->node->children != NULL)
744 return(0);
745 if ((reader->state == XML_TEXTREADER_EMPTY) ||
746 (reader->state == XML_TEXTREADER_BACKTRACK))
747 return(1);
748 return(0);
749}
750
751/**
752 * xmlTextReaderLocalName:
753 * @reader: the xmlTextReaderPtr used
754 *
755 * The local name of the node.
756 *
757 * Returns the local name or NULL if not available
758 */
759xmlChar *
760xmlTextReaderLocalName(xmlTextReaderPtr reader) {
761 if ((reader == NULL) || (reader->node == NULL))
762 return(NULL);
763 if ((reader->node->type != XML_ELEMENT_NODE) &&
764 (reader->node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +0000765 return(xmlTextReaderName(reader));
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000766 return(xmlStrdup(reader->node->name));
767}
768
769/**
770 * xmlTextReaderName:
771 * @reader: the xmlTextReaderPtr used
772 *
773 * The qualified name of the node, equal to Prefix :LocalName.
774 *
775 * Returns the local name or NULL if not available
776 */
777xmlChar *
778xmlTextReaderName(xmlTextReaderPtr reader) {
779 xmlChar *ret;
780
781 if ((reader == NULL) || (reader->node == NULL))
782 return(NULL);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +0000783 switch (reader->node->type) {
784 case XML_ELEMENT_NODE:
785 case XML_ATTRIBUTE_NODE:
786 if ((reader->node->ns == NULL) ||
787 (reader->node->ns->prefix == NULL))
788 return(xmlStrdup(reader->node->name));
789
790 ret = xmlStrdup(reader->node->ns->prefix);
791 ret = xmlStrcat(ret, BAD_CAST ":");
792 ret = xmlStrcat(ret, reader->node->name);
793 return(ret);
794 case XML_TEXT_NODE:
795 return(xmlStrdup(BAD_CAST "#text"));
796 case XML_CDATA_SECTION_NODE:
797 return(xmlStrdup(BAD_CAST "#cdata-section"));
798 case XML_ENTITY_NODE:
799 case XML_ENTITY_REF_NODE:
800 return(xmlStrdup(reader->node->name));
801 case XML_PI_NODE:
802 return(xmlStrdup(reader->node->name));
803 case XML_COMMENT_NODE:
804 return(xmlStrdup(BAD_CAST "#comment"));
805 case XML_DOCUMENT_NODE:
806 case XML_HTML_DOCUMENT_NODE:
807#ifdef LIBXML_DOCB_ENABLED
808 case XML_DOCB_DOCUMENT_NODE:
809#endif
810 return(xmlStrdup(BAD_CAST "#document"));
811 case XML_DOCUMENT_FRAG_NODE:
812 return(xmlStrdup(BAD_CAST "#document-fragment"));
813 case XML_NOTATION_NODE:
814 return(xmlStrdup(reader->node->name));
815 case XML_DOCUMENT_TYPE_NODE:
816 case XML_DTD_NODE:
817 return(xmlStrdup(reader->node->name));
818
819 case XML_ELEMENT_DECL:
820 case XML_ATTRIBUTE_DECL:
821 case XML_ENTITY_DECL:
822 case XML_NAMESPACE_DECL:
823 case XML_XINCLUDE_START:
824 case XML_XINCLUDE_END:
825 return(NULL);
826 }
827 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000828}
829
830/**
831 * xmlTextReaderPrefix:
832 * @reader: the xmlTextReaderPtr used
833 *
834 * A shorthand reference to the namespace associated with the node.
835 *
836 * Returns the prefix or NULL if not available
837 */
838xmlChar *
839xmlTextReaderPrefix(xmlTextReaderPtr reader) {
840 if ((reader == NULL) || (reader->node == NULL))
841 return(NULL);
842 if ((reader->node->type != XML_ELEMENT_NODE) &&
843 (reader->node->type != XML_ATTRIBUTE_NODE))
844 return(NULL);
845 if ((reader->node->ns != NULL) || (reader->node->ns->prefix != NULL))
846 return(xmlStrdup(reader->node->ns->prefix));
847 return(NULL);
848}
849
850/**
851 * xmlTextReaderNamespaceUri:
852 * @reader: the xmlTextReaderPtr used
853 *
854 * The URI defining the namespace associated with the node.
855 *
856 * Returns the namespace URI or NULL if not available
857 */
858xmlChar *
859xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
860 if ((reader == NULL) || (reader->node == NULL))
861 return(NULL);
862 if ((reader->node->type != XML_ELEMENT_NODE) &&
863 (reader->node->type != XML_ATTRIBUTE_NODE))
864 return(NULL);
865 if (reader->node->ns != NULL)
866 return(xmlStrdup(reader->node->ns->href));
867 return(NULL);
868}
869
870/**
871 * xmlTextReaderBaseUri:
872 * @reader: the xmlTextReaderPtr used
873 *
874 * The base URI of the node.
875 *
876 * Returns the base URI or NULL if not available
877 */
878xmlChar *
879xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
880 if ((reader == NULL) || (reader->node == NULL))
881 return(NULL);
882 return(xmlNodeGetBase(NULL, reader->node));
883}
884
885/**
886 * xmlTextReaderDepth:
887 * @reader: the xmlTextReaderPtr used
888 *
889 * The depth of the node in the tree.
890 *
891 * Returns the depth or -1 in case of error
892 */
893int
894xmlTextReaderDepth(xmlTextReaderPtr reader) {
895 if (reader == NULL)
896 return(-1);
897 if (reader->node == NULL)
898 return(0);
899
900 return(reader->depth);
901}
902
903/**
904 * xmlTextReaderHasAttributes:
905 * @reader: the xmlTextReaderPtr used
906 *
907 * Whether the node has attributes.
908 *
909 * Returns 1 if true, 0 if false, and -1 in case or error
910 */
911int
912xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
913 if (reader == NULL)
914 return(-1);
915 if (reader->node == NULL)
916 return(0);
917
918 if ((reader->node->type == XML_ELEMENT_NODE) &&
919 (reader->node->properties != NULL))
920 return(1);
921 /* TODO: handle the xmlDecl */
922 return(0);
923}
924
925/**
926 * xmlTextReaderHasValue:
927 * @reader: the xmlTextReaderPtr used
928 *
929 * Whether the node can have a text value.
930 *
931 * Returns 1 if true, 0 if false, and -1 in case or error
932 */
933int
934xmlTextReaderHasValue(xmlTextReaderPtr reader) {
935 if (reader == NULL)
936 return(-1);
937 if (reader->node == NULL)
938 return(0);
939
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +0000940 switch (reader->node->type) {
941 case XML_ATTRIBUTE_NODE:
942 case XML_TEXT_NODE:
943 case XML_CDATA_SECTION_NODE:
944 case XML_PI_NODE:
945 case XML_COMMENT_NODE:
946 return(1);
947 default:
948 return(0);
949 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000950 return(0);
951}
952
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +0000953/**
954 * xmlTextReaderValue:
955 * @reader: the xmlTextReaderPtr used
956 *
957 * Provides the text value of the node if present
958 *
959 * Returns the string or NULL if not available. The retsult must be deallocated
960 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000961 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +0000962xmlChar *
963xmlTextReaderValue(xmlTextReaderPtr reader) {
964 if (reader == NULL)
965 return(NULL);
966 if (reader->node == NULL)
967 return(NULL);
968
969 switch (reader->node->type) {
970 case XML_ATTRIBUTE_NODE:{
971 xmlAttrPtr attr = (xmlAttrPtr) reader->node;
972
973 if (attr->parent != NULL)
974 return (xmlNodeListGetString
975 (attr->parent->doc, attr->children, 1));
976 else
977 return (xmlNodeListGetString(NULL, attr->children, 1));
978 break;
979 }
980 case XML_TEXT_NODE:
981 case XML_CDATA_SECTION_NODE:
982 case XML_PI_NODE:
983 case XML_COMMENT_NODE:
984 if (reader->node->content != NULL)
985 return (xmlStrdup(reader->node->content));
986 default:
987 return(NULL);
988 }
989 return(NULL);
990}
991
992/**
993 * xmlTextReaderIsDefault:
994 * @reader: the xmlTextReaderPtr used
995 *
996 * Whether an Attribute node was generated from the default value
997 * defined in the DTD or schema.
998 *
999 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
1000 */
1001int
1002xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
1003 if (reader == NULL)
1004 return(-1);
1005 return(0);
1006}
1007
1008/**
1009 * xmlTextReaderQuoteChar:
1010 * @reader: the xmlTextReaderPtr used
1011 *
1012 * The quotation mark character used to enclose the value of an attribute.
1013 *
1014 * Returns " or ' and -1 in case of error
1015 */
1016int
1017xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
1018 if (reader == NULL)
1019 return(-1);
1020 /* TODO maybe lookup the attribute value for " first */
1021 return((int) '"');
1022}
Daniel Veillarde1ca5032002-12-09 14:13:43 +00001023
1024/**
1025 * xmlTextReaderXmlLang:
1026 * @reader: the xmlTextReaderPtr used
1027 *
1028 * The xml:lang scope within which the node resides.
1029 *
1030 * Returns the xml:lang value or NULL if none exists.
1031 */
1032xmlChar *
1033xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
1034 if (reader == NULL)
1035 return(NULL);
1036 if (reader->node == NULL)
1037 return(NULL);
1038 return(xmlNodeGetLang(reader->node));
1039}
1040