blob: 9768492b786aaf70c7835c053c797fb5ff7d52b4 [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))
607 return(NULL);
608 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);
625 if ((reader->node->type != XML_ELEMENT_NODE) &&
626 (reader->node->type != XML_ATTRIBUTE_NODE))
627 return(NULL);
628 if ((reader->node->ns == NULL) || (reader->node->ns->prefix == NULL))
629 return(xmlStrdup(reader->node->name));
630
631 ret = xmlStrdup(reader->node->ns->prefix);
632 ret = xmlStrcat(ret, BAD_CAST ":");
633 ret = xmlStrcat(ret, reader->node->name);
634 return(ret);
635}
636
637/**
638 * xmlTextReaderPrefix:
639 * @reader: the xmlTextReaderPtr used
640 *
641 * A shorthand reference to the namespace associated with the node.
642 *
643 * Returns the prefix or NULL if not available
644 */
645xmlChar *
646xmlTextReaderPrefix(xmlTextReaderPtr reader) {
647 if ((reader == NULL) || (reader->node == NULL))
648 return(NULL);
649 if ((reader->node->type != XML_ELEMENT_NODE) &&
650 (reader->node->type != XML_ATTRIBUTE_NODE))
651 return(NULL);
652 if ((reader->node->ns != NULL) || (reader->node->ns->prefix != NULL))
653 return(xmlStrdup(reader->node->ns->prefix));
654 return(NULL);
655}
656
657/**
658 * xmlTextReaderNamespaceUri:
659 * @reader: the xmlTextReaderPtr used
660 *
661 * The URI defining the namespace associated with the node.
662 *
663 * Returns the namespace URI or NULL if not available
664 */
665xmlChar *
666xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
667 if ((reader == NULL) || (reader->node == NULL))
668 return(NULL);
669 if ((reader->node->type != XML_ELEMENT_NODE) &&
670 (reader->node->type != XML_ATTRIBUTE_NODE))
671 return(NULL);
672 if (reader->node->ns != NULL)
673 return(xmlStrdup(reader->node->ns->href));
674 return(NULL);
675}
676
677/**
678 * xmlTextReaderBaseUri:
679 * @reader: the xmlTextReaderPtr used
680 *
681 * The base URI of the node.
682 *
683 * Returns the base URI or NULL if not available
684 */
685xmlChar *
686xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
687 if ((reader == NULL) || (reader->node == NULL))
688 return(NULL);
689 return(xmlNodeGetBase(NULL, reader->node));
690}
691
692/**
693 * xmlTextReaderDepth:
694 * @reader: the xmlTextReaderPtr used
695 *
696 * The depth of the node in the tree.
697 *
698 * Returns the depth or -1 in case of error
699 */
700int
701xmlTextReaderDepth(xmlTextReaderPtr reader) {
702 if (reader == NULL)
703 return(-1);
704 if (reader->node == NULL)
705 return(0);
706
707 return(reader->depth);
708}
709
710/**
711 * xmlTextReaderHasAttributes:
712 * @reader: the xmlTextReaderPtr used
713 *
714 * Whether the node has attributes.
715 *
716 * Returns 1 if true, 0 if false, and -1 in case or error
717 */
718int
719xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
720 if (reader == NULL)
721 return(-1);
722 if (reader->node == NULL)
723 return(0);
724
725 if ((reader->node->type == XML_ELEMENT_NODE) &&
726 (reader->node->properties != NULL))
727 return(1);
728 /* TODO: handle the xmlDecl */
729 return(0);
730}
731
732/**
733 * xmlTextReaderHasValue:
734 * @reader: the xmlTextReaderPtr used
735 *
736 * Whether the node can have a text value.
737 *
738 * Returns 1 if true, 0 if false, and -1 in case or error
739 */
740int
741xmlTextReaderHasValue(xmlTextReaderPtr reader) {
742 if (reader == NULL)
743 return(-1);
744 if (reader->node == NULL)
745 return(0);
746
747 TODO
748 return(0);
749}
750
751/*
752int xmlTextReaderIsDefault (xmlTextReaderPtr reader);
753int xmlTextReaderQuoteChar (xmlTextReaderPtr reader);
754xmlChar * xmlTextReaderValue (xmlTextReaderPtr reader);
755 */
756
757/**
758 * xmlTextReaderXmlLang:
759 * @reader: the xmlTextReaderPtr used
760 *
761 * The xml:lang scope within which the node resides.
762 *
763 * Returns the xml:lang value or NULL if none exists.
764 */
765xmlChar *
766xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
767 if (reader == NULL)
768 return(NULL);
769 if (reader->node == NULL)
770 return(NULL);
771 return(xmlNodeGetLang(reader->node));
772}
773