blob: 65ca8e8ae1b2148fe0f84d02c45b2dc0829e5f4f [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,
56 XML_TEXTREADER_MODE_EOF = 1
57} xmlTextReaderMode;
58
59typedef enum {
60 XML_TEXTREADER_NONE = -1,
61 XML_TEXTREADER_START= 0,
62 XML_TEXTREADER_ELEMENT= 1,
63 XML_TEXTREADER_END= 2,
64 XML_TEXTREADER_EMPTY= 3,
65 XML_TEXTREADER_BACKTRACK= 4
66} xmlTextReaderState;
67
68struct _xmlTextReader {
69 int mode; /* the parsing mode */
70 int allocs; /* what structure were deallocated */
71 xmlTextReaderState state;
72 xmlParserCtxtPtr ctxt; /* the parser context */
73 xmlSAXHandlerPtr sax; /* the parser SAX callbacks */
74 xmlParserInputBufferPtr input; /* the input */
75 startElementSAXFunc startElement;/* initial SAX callbacks */
76 endElementSAXFunc endElement; /* idem */
77 unsigned int base; /* base of the segment in the input */
78 unsigned int cur; /* current position in the input */
79 xmlNodePtr node; /* current node */
80 int depth; /* depth of the current node */
81};
82
83#ifdef DEBUG_READER
84static void
85xmlTextReaderDebug(xmlTextReaderPtr reader) {
86 if ((reader == NULL) || (reader->ctxt == NULL)) {
87 fprintf(stderr, "xmlTextReader NULL\n");
88 return;
89 }
90 fprintf(stderr, "xmlTextReader: state %d depth %d ",
91 reader->state, reader->depth);
92 if (reader->node == NULL) {
93 fprintf(stderr, "node = NULL\n");
94 } else {
95 fprintf(stderr, "node %s\n", reader->node->name);
96 }
97 fprintf(stderr, " input: base %d, cur %d, depth %d: ",
98 reader->base, reader->cur, reader->ctxt->nodeNr);
99 if (reader->input->buffer == NULL) {
100 fprintf(stderr, "buffer is NULL\n");
101 } else {
102#ifdef LIBXML_DEBUG_ENABLED
103 xmlDebugDumpString(stderr,
104 &reader->input->buffer->content[reader->cur]);
105#endif
106 fprintf(stderr, "\n");
107 }
108}
109#endif
110
111/**
112 * xmlTextReaderStartElement:
113 * @ctx: the user data (XML parser context)
114 * @fullname: The element name, including namespace prefix
115 * @atts: An array of name/value attributes pairs, NULL terminated
116 *
117 * called when an opening tag has been processed.
118 */
119static void
120xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
121 const xmlChar **atts) {
122 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
123 xmlTextReaderPtr reader = ctxt->_private;
124
125#ifdef DEBUG_CALLBACKS
126 printf("xmlTextReaderStartElement(%s)\n", fullname);
127#endif
128 if ((reader != NULL) && (reader->startElement != NULL))
129 reader->startElement(ctx, fullname, atts);
130 reader->state = XML_TEXTREADER_ELEMENT;
131}
132
133/**
134 * xmlTextReaderEndElement:
135 * @ctx: the user data (XML parser context)
136 * @fullname: The element name, including namespace prefix
137 *
138 * called when an ending tag has been processed.
139 */
140static void
141xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
142 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
143 xmlTextReaderPtr reader = ctxt->_private;
144
145#ifdef DEBUG_CALLBACKS
146 printf("xmlTextReaderEndElement(%s)\n", fullname);
147#endif
148 if ((reader != NULL) && (reader->endElement != NULL))
149 reader->endElement(ctx, fullname);
150 if (reader->state == XML_TEXTREADER_ELEMENT)
151 reader->state = XML_TEXTREADER_EMPTY;
152 else
153 reader->state = XML_TEXTREADER_END;
154}
155
156/**
157 * xmlTextReaderPushData:
158 * @reader: the xmlTextReaderPtr used
159 *
160 * Push data down the progressive parser until a significant callback
161 * got raised.
162 *
163 * Returns -1 in case of failure, 0 otherwise
164 */
165static int
166xmlTextReaderPushData(xmlTextReaderPtr reader) {
167 unsigned int cur = reader->cur;
168 xmlBufferPtr inbuf;
169 int val;
170
171 if ((reader->input == NULL) || (reader->input->buffer == NULL))
172 return(-1);
173
174 reader->state = XML_TEXTREADER_NONE;
175 inbuf = reader->input->buffer;
176 while (reader->state == XML_TEXTREADER_NONE) {
177 if (cur >= inbuf->use) {
178 /*
179 * Refill the buffer unless we are at the end of the stream
180 */
181 if (reader->mode != XML_TEXTREADER_MODE_EOF) {
182 val = xmlParserInputBufferRead(reader->input, 4096);
183 if (val <= 0) {
184 reader->mode = XML_TEXTREADER_MODE_EOF;
185 return(val);
186 }
187 } else
188 break;
189 }
190 if ((inbuf->content[cur] == '>') || (inbuf->content[cur] == '&')) {
191 cur = cur + 1;
192 val = xmlParseChunk(reader->ctxt,
193 (const char *) &inbuf->content[reader->cur],
194 cur - reader->cur, 0);
195 if (val != 0)
196 return(-1);
197 reader->cur = cur;
198 break;
199 } else {
200 cur = cur + 1;
201
202 /*
203 * One may have to force a flush at some point when parsing really
204 * large CDATA sections
205 */
206 if ((cur - reader->cur > 4096) && (reader->base == 0) &&
207 (reader->mode == XML_TEXTREADER_MODE_NORMAL)) {
208 cur = cur + 1;
209 val = xmlParseChunk(reader->ctxt,
210 (const char *) &inbuf->content[reader->cur],
211 cur - reader->cur, 0);
212 if (val != 0)
213 return(-1);
214 reader->cur = cur;
215 }
216 }
217 }
218 /*
219 * Discard the consumed input when needed and possible
220 */
221 if (reader->mode == XML_TEXTREADER_MODE_NORMAL) {
222 if ((reader->cur >= 4096) && (reader->base == 0)) {
223 val = xmlBufferShrink(inbuf, cur);
224 if (val >= 0) {
225 reader->cur -= val;
226 }
227 }
228 }
229
230 /*
231 * At the end of the stream signal that the work is done to the Push
232 * parser.
233 */
234 if ((reader->mode == XML_TEXTREADER_MODE_EOF) && (cur >= inbuf->use)) {
235 val = xmlParseChunk(reader->ctxt,
236 (const char *) &inbuf->content[reader->cur], 0, 1);
237 }
238 return(0);
239}
240
241/**
242 * xmlTextReaderRead:
243 * @reader: the xmlTextReaderPtr used
244 *
245 * Moves the position of the current instance to the next node in
246 * the stream, exposing its properties.
247 *
248 * Returns 1 if the node was read successfully, 0 if there is no more
249 * nodes to read, or -1 in case of error
250 */
251int
252xmlTextReaderRead(xmlTextReaderPtr reader) {
253 int val, olddepth;
254 xmlTextReaderState oldstate;
255 xmlNodePtr oldnode;
256
257 if ((reader == NULL) || (reader->ctxt == NULL))
258 return(-1);
259 if (reader->ctxt->wellFormed != 1)
260 return(-1);
261
262#ifdef DEBUG_READER
263 fprintf(stderr, "\nREAD ");
264 DUMP_READER
265#endif
266 if (reader->node == NULL) {
267 /*
268 * Initial state
269 */
270 do {
271 val = xmlTextReaderPushData(reader);
272 if (val < 0)
273 return(-1);
274 } while ((reader->ctxt->node == NULL) &&
275 (reader->mode != XML_TEXTREADER_MODE_EOF));
276 if (reader->ctxt->node == NULL) {
277 if (reader->ctxt->myDoc != NULL)
278 reader->node = reader->ctxt->myDoc->children;
279 if (reader->node == NULL)
280 return(-1);
281 } else {
282 reader->node = reader->ctxt->node;
283 }
284 reader->depth = 1;
285 return(1);
286 }
287 oldstate = reader->state;
288 olddepth = reader->ctxt->nodeNr;
289 oldnode = reader->node;
290 /*
291 * If we are not backtracking on ancestors or examined nodes,
292 * that the parser didn't finished or that we arent at the end
293 * of stream, continue processing.
294 */
295 if (oldstate != XML_TEXTREADER_BACKTRACK) {
296 while (((reader->node->children == NULL) ||
297 (reader->node->type == XML_ENTITY_REF_NODE) ||
298 (reader->node->type == XML_DTD_NODE)) &&
299 (reader->node->next == NULL) &&
300 (reader->ctxt->nodeNr == olddepth) &&
301 (reader->ctxt->instate != XML_PARSER_EOF)) {
302 val = xmlTextReaderPushData(reader);
303 if (val < 0)
304 return(-1);
305 if (reader->node == NULL)
306 return(0);
307 }
308 if ((reader->node->children != NULL) &&
309 (reader->node->type != XML_ENTITY_REF_NODE) &&
310 (reader->node->type != XML_DTD_NODE)) {
311 reader->node = reader->node->children;
312 reader->depth++;
313 if ((reader->state != XML_TEXTREADER_ELEMENT) &&
314 (reader->state != XML_TEXTREADER_EMPTY))
315 reader->state = XML_TEXTREADER_ELEMENT;
316 DUMP_READER
317 return(1);
318 }
319 }
320 if (reader->node->next != NULL) {
321 if ((oldstate == XML_TEXTREADER_ELEMENT) &&
322 (reader->node->type == XML_ELEMENT_NODE)) {
323 reader->state = XML_TEXTREADER_END;
324 DUMP_READER
325 return(1);
326 }
327 reader->node = reader->node->next;
328 reader->state = XML_TEXTREADER_ELEMENT;
329 DUMP_READER
330 /*
331 * Cleanup of the old node
332 */
333 if (oldnode->type != XML_DTD_NODE) {
334 xmlUnlinkNode(oldnode);
335 xmlFreeNode(oldnode);
336 }
337
338 return(1);
339 }
340 reader->node = reader->node->parent;
341 if ((reader->node == NULL) ||
342 (reader->node->type == XML_DOCUMENT_NODE) ||
343#ifdef LIBXML_DOCB_ENABLED
344 (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
345#endif
346 (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
347 reader->node = NULL;
348 reader->depth = 0;
349
350 /*
351 * Cleanup of the old node
352 */
353 if (oldnode->type != XML_DTD_NODE) {
354 xmlUnlinkNode(oldnode);
355 xmlFreeNode(oldnode);
356 }
357
358 return(0);
359 }
360 reader->depth--;
361 reader->state = XML_TEXTREADER_BACKTRACK;
362 DUMP_READER
363 return(1);
364}
365
366/************************************************************************
367 * *
368 * Constructor and destructors *
369 * *
370 ************************************************************************/
371/**
372 * xmlNewTextReader:
373 * @input: the xmlParserInputBufferPtr used to read data
374 *
375 * Create an xmlTextReader structure fed with @input
376 *
377 * Returns the new xmlTextReaderPtr or NULL in case of error
378 */
379xmlTextReaderPtr
380xmlNewTextReader(xmlParserInputBufferPtr input) {
381 xmlTextReaderPtr ret;
382 int val;
383
384 if (input == NULL)
385 return(NULL);
386 ret = xmlMalloc(sizeof(xmlTextReader));
387 if (ret == NULL) {
388 xmlGenericError(xmlGenericErrorContext,
389 "xmlNewTextReader : malloc failed\n");
390 return(NULL);
391 }
392 memset(ret, 0, sizeof(xmlTextReader));
393 ret->input = input;
394 ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
395 if (ret->sax == NULL) {
396 xmlFree(ret);
397 xmlGenericError(xmlGenericErrorContext,
398 "xmlNewTextReader : malloc failed\n");
399 return(NULL);
400 }
401 memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
402 ret->startElement = ret->sax->startElement;
403 ret->sax->startElement = xmlTextReaderStartElement;
404 ret->endElement = ret->sax->endElement;
405 ret->sax->endElement = xmlTextReaderEndElement;
406
407 ret->mode = XML_TEXTREADER_MODE_NORMAL;
408 ret->node = NULL;
409 val = xmlParserInputBufferRead(input, 4);
410 if (val >= 4) {
411 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
412 (const char *) ret->input->buffer->content, 4, NULL);
413 ret->base = 0;
414 ret->cur = 4;
415 } else {
416 ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, NULL);
417 ret->base = 0;
418 ret->cur = 0;
419 }
420 ret->ctxt->_private = ret;
421 ret->allocs = XML_TEXTREADER_CTXT;
422 return(ret);
423
424}
425
426/**
427 * xmlNewTextReaderFilename:
428 * @URI: the URI of the resource to process
429 *
430 * Create an xmlTextReader structure fed with the resource at @URI
431 *
432 * Returns the new xmlTextReaderPtr or NULL in case of error
433 */
434xmlTextReaderPtr
435xmlNewTextReaderFilename(const char *URI) {
436 xmlParserInputBufferPtr input;
437 xmlTextReaderPtr ret;
438
439 input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
440 if (input == NULL)
441 return(NULL);
442 ret = xmlNewTextReader(input);
443 if (ret == NULL) {
444 xmlFreeParserInputBuffer(input);
445 return(NULL);
446 }
447 ret->allocs |= XML_TEXTREADER_INPUT;
448 return(ret);
449}
450
451/**
452 * xmlFreeTextReader:
453 * @reader: the xmlTextReaderPtr
454 *
455 * Deallocate all the resources associated to the reader
456 */
457void
458xmlFreeTextReader(xmlTextReaderPtr reader) {
459 if (reader == NULL)
460 return;
461 if (reader->ctxt != NULL) {
462 if (reader->ctxt->myDoc != NULL) {
463 xmlFreeDoc(reader->ctxt->myDoc);
464 reader->ctxt->myDoc = NULL;
465 }
466 if (reader->allocs & XML_TEXTREADER_CTXT)
467 xmlFreeParserCtxt(reader->ctxt);
468 }
469 if (reader->sax != NULL)
470 xmlFree(reader->sax);
471 if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT))
472 xmlFreeParserInputBuffer(reader->input);
473 xmlFree(reader);
474}
475
476/************************************************************************
477 * *
478 * Acces API to the current node *
479 * *
480 ************************************************************************/
481/**
482 * xmlTextReaderAttributeCount:
483 * @reader: the xmlTextReaderPtr used
484 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000485 * Provides the number of attributes of the current node
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000486 *
487 * Returns 0 i no attributes, -1 in case of error or the attribute count
488 */
489int
490xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
491 int ret;
492 xmlAttrPtr attr;
493
494 if (reader == NULL)
495 return(-1);
496 if (reader->node == NULL)
497 return(0);
498 if (reader->node->type != XML_ELEMENT_NODE)
499 return(0);
500 if ((reader->state == XML_TEXTREADER_END) ||
501 (reader->state == XML_TEXTREADER_BACKTRACK))
502 return(0);
503 ret = 0;
504 attr = reader->node->properties;
505 while (attr != NULL) {
506 ret++;
507 attr = attr->next;
508 }
509 return(ret);
510}
511
512/**
513 * xmlTextReaderNodeType:
514 * @reader: the xmlTextReaderPtr used
515 *
516 * Get the node type of the current node
517 * Reference:
518 * http://dotgnu.org/pnetlib-doc/System/Xml/XmlNodeType.html
519 *
520 * Returns the xmlNodeType of the current node or -1 in case of error
521 */
522int
523xmlTextReaderNodeType(xmlTextReaderPtr reader) {
524 if (reader == NULL)
525 return(-1);
526 if (reader->node == NULL)
527 return(0);
528 switch (reader->node->type) {
529 case XML_ELEMENT_NODE:
530 if ((reader->state == XML_TEXTREADER_END) ||
531 (reader->state == XML_TEXTREADER_BACKTRACK))
532 return(15);
533 return(1);
534 case XML_ATTRIBUTE_NODE:
535 return(2);
536 case XML_TEXT_NODE:
537 return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
538 case XML_CDATA_SECTION_NODE:
539 return(4);
540 case XML_ENTITY_REF_NODE:
541 return(5);
542 case XML_ENTITY_NODE:
543 return(6);
544 case XML_PI_NODE:
545 return(7);
546 case XML_COMMENT_NODE:
547 return(8);
548 case XML_DOCUMENT_NODE:
549 case XML_HTML_DOCUMENT_NODE:
550#ifdef LIBXML_DOCB_ENABLED
551 case XML_DOCB_DOCUMENT_NODE:
552#endif
553 return(9);
554 case XML_DOCUMENT_FRAG_NODE:
555 return(11);
556 case XML_NOTATION_NODE:
557 return(12);
558 case XML_DOCUMENT_TYPE_NODE:
559 case XML_DTD_NODE:
560 return(10);
561
562 case XML_ELEMENT_DECL:
563 case XML_ATTRIBUTE_DECL:
564 case XML_ENTITY_DECL:
565 case XML_NAMESPACE_DECL:
566 case XML_XINCLUDE_START:
567 case XML_XINCLUDE_END:
568 return(0);
569 }
570 return(-1);
571}
572
573/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000574 * xmlTextReaderIsEmptyElement:
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000575 * @reader: the xmlTextReaderPtr used
576 *
577 * Check if the current node is empty
578 *
579 * Returns 1 if empty, 0 if not and -1 in case of error
580 */
581int
582xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
583 if ((reader == NULL) || (reader->node == NULL))
584 return(-1);
585 if (reader->node->children != NULL)
586 return(0);
587 if ((reader->state == XML_TEXTREADER_EMPTY) ||
588 (reader->state == XML_TEXTREADER_BACKTRACK))
589 return(1);
590 return(0);
591}
592
593/**
594 * xmlTextReaderLocalName:
595 * @reader: the xmlTextReaderPtr used
596 *
597 * The local name of the node.
598 *
599 * Returns the local name or NULL if not available
600 */
601xmlChar *
602xmlTextReaderLocalName(xmlTextReaderPtr reader) {
603 if ((reader == NULL) || (reader->node == NULL))
604 return(NULL);
605 if ((reader->node->type != XML_ELEMENT_NODE) &&
606 (reader->node->type != XML_ATTRIBUTE_NODE))
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +0000607 return(xmlTextReaderName(reader));
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000608 return(xmlStrdup(reader->node->name));
609}
610
611/**
612 * xmlTextReaderName:
613 * @reader: the xmlTextReaderPtr used
614 *
615 * The qualified name of the node, equal to Prefix :LocalName.
616 *
617 * Returns the local name or NULL if not available
618 */
619xmlChar *
620xmlTextReaderName(xmlTextReaderPtr reader) {
621 xmlChar *ret;
622
623 if ((reader == NULL) || (reader->node == NULL))
624 return(NULL);
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +0000625 switch (reader->node->type) {
626 case XML_ELEMENT_NODE:
627 case XML_ATTRIBUTE_NODE:
628 if ((reader->node->ns == NULL) ||
629 (reader->node->ns->prefix == NULL))
630 return(xmlStrdup(reader->node->name));
631
632 ret = xmlStrdup(reader->node->ns->prefix);
633 ret = xmlStrcat(ret, BAD_CAST ":");
634 ret = xmlStrcat(ret, reader->node->name);
635 return(ret);
636 case XML_TEXT_NODE:
637 return(xmlStrdup(BAD_CAST "#text"));
638 case XML_CDATA_SECTION_NODE:
639 return(xmlStrdup(BAD_CAST "#cdata-section"));
640 case XML_ENTITY_NODE:
641 case XML_ENTITY_REF_NODE:
642 return(xmlStrdup(reader->node->name));
643 case XML_PI_NODE:
644 return(xmlStrdup(reader->node->name));
645 case XML_COMMENT_NODE:
646 return(xmlStrdup(BAD_CAST "#comment"));
647 case XML_DOCUMENT_NODE:
648 case XML_HTML_DOCUMENT_NODE:
649#ifdef LIBXML_DOCB_ENABLED
650 case XML_DOCB_DOCUMENT_NODE:
651#endif
652 return(xmlStrdup(BAD_CAST "#document"));
653 case XML_DOCUMENT_FRAG_NODE:
654 return(xmlStrdup(BAD_CAST "#document-fragment"));
655 case XML_NOTATION_NODE:
656 return(xmlStrdup(reader->node->name));
657 case XML_DOCUMENT_TYPE_NODE:
658 case XML_DTD_NODE:
659 return(xmlStrdup(reader->node->name));
660
661 case XML_ELEMENT_DECL:
662 case XML_ATTRIBUTE_DECL:
663 case XML_ENTITY_DECL:
664 case XML_NAMESPACE_DECL:
665 case XML_XINCLUDE_START:
666 case XML_XINCLUDE_END:
667 return(NULL);
668 }
669 return(NULL);
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000670}
671
672/**
673 * xmlTextReaderPrefix:
674 * @reader: the xmlTextReaderPtr used
675 *
676 * A shorthand reference to the namespace associated with the node.
677 *
678 * Returns the prefix or NULL if not available
679 */
680xmlChar *
681xmlTextReaderPrefix(xmlTextReaderPtr reader) {
682 if ((reader == NULL) || (reader->node == NULL))
683 return(NULL);
684 if ((reader->node->type != XML_ELEMENT_NODE) &&
685 (reader->node->type != XML_ATTRIBUTE_NODE))
686 return(NULL);
687 if ((reader->node->ns != NULL) || (reader->node->ns->prefix != NULL))
688 return(xmlStrdup(reader->node->ns->prefix));
689 return(NULL);
690}
691
692/**
693 * xmlTextReaderNamespaceUri:
694 * @reader: the xmlTextReaderPtr used
695 *
696 * The URI defining the namespace associated with the node.
697 *
698 * Returns the namespace URI or NULL if not available
699 */
700xmlChar *
701xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
702 if ((reader == NULL) || (reader->node == NULL))
703 return(NULL);
704 if ((reader->node->type != XML_ELEMENT_NODE) &&
705 (reader->node->type != XML_ATTRIBUTE_NODE))
706 return(NULL);
707 if (reader->node->ns != NULL)
708 return(xmlStrdup(reader->node->ns->href));
709 return(NULL);
710}
711
712/**
713 * xmlTextReaderBaseUri:
714 * @reader: the xmlTextReaderPtr used
715 *
716 * The base URI of the node.
717 *
718 * Returns the base URI or NULL if not available
719 */
720xmlChar *
721xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
722 if ((reader == NULL) || (reader->node == NULL))
723 return(NULL);
724 return(xmlNodeGetBase(NULL, reader->node));
725}
726
727/**
728 * xmlTextReaderDepth:
729 * @reader: the xmlTextReaderPtr used
730 *
731 * The depth of the node in the tree.
732 *
733 * Returns the depth or -1 in case of error
734 */
735int
736xmlTextReaderDepth(xmlTextReaderPtr reader) {
737 if (reader == NULL)
738 return(-1);
739 if (reader->node == NULL)
740 return(0);
741
742 return(reader->depth);
743}
744
745/**
746 * xmlTextReaderHasAttributes:
747 * @reader: the xmlTextReaderPtr used
748 *
749 * Whether the node has attributes.
750 *
751 * Returns 1 if true, 0 if false, and -1 in case or error
752 */
753int
754xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
755 if (reader == NULL)
756 return(-1);
757 if (reader->node == NULL)
758 return(0);
759
760 if ((reader->node->type == XML_ELEMENT_NODE) &&
761 (reader->node->properties != NULL))
762 return(1);
763 /* TODO: handle the xmlDecl */
764 return(0);
765}
766
767/**
768 * xmlTextReaderHasValue:
769 * @reader: the xmlTextReaderPtr used
770 *
771 * Whether the node can have a text value.
772 *
773 * Returns 1 if true, 0 if false, and -1 in case or error
774 */
775int
776xmlTextReaderHasValue(xmlTextReaderPtr reader) {
777 if (reader == NULL)
778 return(-1);
779 if (reader->node == NULL)
780 return(0);
781
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +0000782 switch (reader->node->type) {
783 case XML_ATTRIBUTE_NODE:
784 case XML_TEXT_NODE:
785 case XML_CDATA_SECTION_NODE:
786 case XML_PI_NODE:
787 case XML_COMMENT_NODE:
788 return(1);
789 default:
790 return(0);
791 }
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000792 return(0);
793}
794
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +0000795/**
796 * xmlTextReaderValue:
797 * @reader: the xmlTextReaderPtr used
798 *
799 * Provides the text value of the node if present
800 *
801 * Returns the string or NULL if not available. The retsult must be deallocated
802 * with xmlFree()
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000803 */
Daniel Veillard9b4bb4d2002-12-11 19:28:47 +0000804xmlChar *
805xmlTextReaderValue(xmlTextReaderPtr reader) {
806 if (reader == NULL)
807 return(NULL);
808 if (reader->node == NULL)
809 return(NULL);
810
811 switch (reader->node->type) {
812 case XML_ATTRIBUTE_NODE:{
813 xmlAttrPtr attr = (xmlAttrPtr) reader->node;
814
815 if (attr->parent != NULL)
816 return (xmlNodeListGetString
817 (attr->parent->doc, attr->children, 1));
818 else
819 return (xmlNodeListGetString(NULL, attr->children, 1));
820 break;
821 }
822 case XML_TEXT_NODE:
823 case XML_CDATA_SECTION_NODE:
824 case XML_PI_NODE:
825 case XML_COMMENT_NODE:
826 if (reader->node->content != NULL)
827 return (xmlStrdup(reader->node->content));
828 default:
829 return(NULL);
830 }
831 return(NULL);
832}
833
834/**
835 * xmlTextReaderIsDefault:
836 * @reader: the xmlTextReaderPtr used
837 *
838 * Whether an Attribute node was generated from the default value
839 * defined in the DTD or schema.
840 *
841 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
842 */
843int
844xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
845 if (reader == NULL)
846 return(-1);
847 return(0);
848}
849
850/**
851 * xmlTextReaderQuoteChar:
852 * @reader: the xmlTextReaderPtr used
853 *
854 * The quotation mark character used to enclose the value of an attribute.
855 *
856 * Returns " or ' and -1 in case of error
857 */
858int
859xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
860 if (reader == NULL)
861 return(-1);
862 /* TODO maybe lookup the attribute value for " first */
863 return((int) '"');
864}
Daniel Veillarde1ca5032002-12-09 14:13:43 +0000865
866/**
867 * xmlTextReaderXmlLang:
868 * @reader: the xmlTextReaderPtr used
869 *
870 * The xml:lang scope within which the node resides.
871 *
872 * Returns the xml:lang value or NULL if none exists.
873 */
874xmlChar *
875xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
876 if (reader == NULL)
877 return(NULL);
878 if (reader->node == NULL)
879 return(NULL);
880 return(xmlNodeGetLang(reader->node));
881}
882