From e72c508cd0c7a829602906f54fa8a29abaf3afa6 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Fri, 19 Sep 2003 12:44:05 +0000 Subject: [PATCH] preparing a 2.6.0-beta2 release avoid a warning avoid duplicate code in * configure.in: preparing a 2.6.0-beta2 release * xmlIO.c: avoid a warning * tree.c: avoid duplicate code in xmlReplaceNode as pointed out by Chris Ryland * include/libxml/dict.h: add a QName access lookup to the dictionary. * xmlreader.c include/libxml/xmlreader.h: adding const access based on the dictionary interface for string read from the reader, the node content access is still TODO, it's too different Daniel --- ChangeLog | 12 +++ configure.in | 2 +- dict.c | 198 ++++++++++++++++++++++++++++++++-- doc/libxml2-api.xml | 98 +++++++++++++++-- include/libxml/dict.h | 4 + include/libxml/xmlreader.h | 32 ++++-- python/libxml2class.txt | 6 ++ tree.c | 16 +-- xmlIO.c | 2 +- xmlreader.c | 216 +++++++++++++++++++++++++++++++++++++ 10 files changed, 544 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index 17128543..6ec57ffa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +Fri Sep 19 14:26:28 CEST 2003 Daniel Veillard + + * configure.in: preparing a 2.6.0-beta2 release + * xmlIO.c: avoid a warning + * tree.c: avoid duplicate code in xmlReplaceNode as pointed out + by Chris Ryland + * include/libxml/dict.h: add a QName access lookup to the + dictionary. + * xmlreader.c include/libxml/xmlreader.h: adding const access + based on the dictionary interface for string read from the + reader, the node content access is still TODO, it's too different + Fri Sep 19 00:01:08 CEST 2003 Daniel Veillard * SAX2.c: fixing namespace DTD validations diff --git a/configure.in b/configure.in index a954eae0..e8de6d06 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_CANONICAL_HOST LIBXML_MAJOR_VERSION=2 LIBXML_MINOR_VERSION=6 LIBXML_MICRO_VERSION=0 -LIBXML_MICRO_VERSION_SUFFIX=beta1 +LIBXML_MICRO_VERSION_SUFFIX=beta2 LIBXML_VERSION=$LIBXML_MAJOR_VERSION.$LIBXML_MINOR_VERSION.$LIBXML_MICRO_VERSION$LIBXML_MICRO_VERSION_SUFFIX LIBXML_VERSION_INFO=`expr $LIBXML_MAJOR_VERSION + $LIBXML_MINOR_VERSION`:$LIBXML_MICRO_VERSION:$LIBXML_MINOR_VERSION diff --git a/dict.c b/dict.c index 20d1efb5..93c8b8ed 100644 --- a/dict.c +++ b/dict.c @@ -114,6 +114,66 @@ found_pool: return(ret); } +/* + * xmlDictAddQString: + * @dict: the dictionnary + * @prefix: the prefix of the userdata + * @name: the name of the userdata + * @len: the length of the name, if -1 it is recomputed + * + * Add the QName to the array[s] + * + * Returns the pointer of the local string, or NULL in case of error. + */ +static const xmlChar * +xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, + const xmlChar *name, int namelen) +{ + xmlDictStringsPtr pool; + const xmlChar *ret; + int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ + int plen; + + if (prefix == NULL) return(xmlDictAddString(dict, name, namelen)); + plen = xmlStrlen(prefix); + + pool = dict->strings; + while (pool != NULL) { + if (pool->end - pool->free > namelen) + goto found_pool; + if (pool->size > size) size = pool->size; + pool = pool->next; + } + /* + * Not found, need to allocate + */ + if (pool == NULL) { + if (size == 0) size = 1000; + else size *= 4; /* exponential growth */ + if (size < 4 * namelen) + size = 4 * namelen; /* just in case ! */ + pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size); + if (pool == NULL) + return(NULL); + pool->size = size; + pool->nbStrings = 0; + pool->free = &pool->array[0]; + pool->end = &pool->array[size]; + pool->next = dict->strings; + dict->strings = pool; + } +found_pool: + ret = pool->free; + memcpy(pool->free, prefix, plen); + pool->free += plen; + *(pool->free++) = ':'; + namelen -= plen + 1; + memcpy(pool->free, name, namelen); + pool->free += namelen; + *(pool->free++) = 0; + return(ret); +} + /* * xmlDictComputeKey: * Calculate the hash key @@ -141,16 +201,66 @@ xmlDictComputeKey(xmlDictPtr dict, const xmlChar *name, int namelen) { case 1: value += name[0]; default: break; } -#if 0 - while ((len++ < namelen) && ((ch = *name++) != 0)) { - value += (unsigned long)ch; + return (value % dict->size); +} + +/* + * xmlDictComputeQKey: + * Calculate the hash key + */ +static unsigned long +xmlDictComputeQKey(xmlDictPtr dict, const xmlChar *prefix, + const xmlChar *name, int len) +{ + unsigned long value = 0L; + int plen; + + if (prefix == NULL) + return(xmlDictComputeKey(dict, name, len)); + + plen = xmlStrlen(prefix); + if (plen == 0) + value += 30 * (unsigned long) ':'; + else + value += 30 * (*prefix); + + if (len > 10) { + value += name[len - (plen + 1 + 1)]; + len = 10; + if (plen > 10) + plen = 10; } -#endif -#if 0 - while ((len++ < namelen) && ((ch = *name++) != 0)) { - value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + switch (plen) { + case 10: value += prefix[9]; + case 9: value += prefix[8]; + case 8: value += prefix[7]; + case 7: value += prefix[6]; + case 6: value += prefix[5]; + case 5: value += prefix[4]; + case 4: value += prefix[3]; + case 3: value += prefix[2]; + case 2: value += prefix[1]; + case 1: value += prefix[0]; + default: break; + } + len -= plen; + if (len > 0) { + value += (unsigned long) ':'; + len--; + } + switch (len) { + case 10: value += name[9]; + case 9: value += name[8]; + case 8: value += name[7]; + case 7: value += name[6]; + case 6: value += name[5]; + case 5: value += name[4]; + case 4: value += name[3]; + case 3: value += name[2]; + case 2: value += name[1]; + case 1: value += name[0]; + default: break; } -#endif return (value % dict->size); } @@ -389,6 +499,78 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) { return(ret); } +/** + * xmlDictQLookup: + * @dict: the dictionnary + * @prefix: the prefix + * @name: the name + * + * Add the QName @prefix:@name to the hash @dict if not present. + * + * Returns the internal copy of the QName or NULL in case of internal error + */ +const xmlChar * +xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) { + unsigned long key, nbi = 0; + xmlDictEntryPtr entry; + xmlDictEntryPtr insert; + const xmlChar *ret; + int len; + + if ((dict == NULL) || (name == NULL)) + return(NULL); + + len = xmlStrlen(name); + if (prefix != NULL) + len += 1 + xmlStrlen(prefix); + + /* + * Check for duplicate and insertion location. + */ + key = xmlDictComputeQKey(dict, prefix, name, len); + if (dict->dict[key].valid == 0) { + insert = NULL; + } else { + for (insert = &(dict->dict[key]); insert->next != NULL; + insert = insert->next) { + if ((insert->len == len) && + (xmlStrQEqual(prefix, name, insert->name))) + return(insert->name); + nbi++; + } + if ((insert->len == len) && + (xmlStrQEqual(prefix, name, insert->name))) + return(insert->name); + } + + ret = xmlDictAddQString(dict, prefix, name, len); + if (ret == NULL) + return(NULL); + if (insert == NULL) { + entry = &(dict->dict[key]); + } else { + entry = xmlMalloc(sizeof(xmlDictEntry)); + if (entry == NULL) + return(NULL); + } + entry->name = ret; + entry->len = len; + entry->next = NULL; + entry->valid = 1; + + if (insert != NULL) + insert->next = entry; + + dict->nbElems++; + + if ((nbi > MAX_HASH_LEN) && + (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) + xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size); + /* Note that entry may have been freed at this point by xmlDictGrow */ + + return(ret); +} + /** * xmlDictOwns: * @dict: the dictionnary diff --git a/doc/libxml2-api.xml b/doc/libxml2-api.xml index f7b89188..d6811813 100644 --- a/doc/libxml2-api.xml +++ b/doc/libxml2-api.xml @@ -518,7 +518,6 @@ - @@ -527,7 +526,6 @@ - @@ -858,6 +856,7 @@ + @@ -1296,6 +1295,12 @@ + + + + + + @@ -1469,7 +1474,9 @@ + + @@ -1629,6 +1636,7 @@ + @@ -1707,8 +1715,13 @@ + + + + + @@ -1743,6 +1756,7 @@ + @@ -1814,6 +1828,7 @@ + @@ -2673,6 +2688,7 @@ + @@ -2742,6 +2758,7 @@ + @@ -2791,7 +2808,7 @@ - + @@ -2820,6 +2837,7 @@ + @@ -2831,6 +2849,10 @@ + + + + @@ -3020,12 +3042,10 @@ - - @@ -3435,6 +3455,13 @@ actually an xmlCharEncoding'/> + + + + + + @@ -3456,6 +3483,7 @@ actually an xmlCharEncoding'/> + @@ -5127,6 +5155,12 @@ actually an xmlCharEncoding'/> + + routine to create an XML buffer from an immutable memory area, The are won't be modified nor copied, and is expected to be present until the end of the buffer lifetime. + + + + Dumps an XML buffer to a FILE *. @@ -5754,6 +5788,19 @@ actually an xmlCharEncoding'/> + + check if a string is owned by the disctionary + + + + + + Add the QName @prefix:@name to the hash @dict if not present. + + + + + Query the number of elements installed in the hash @dict. @@ -7814,7 +7861,7 @@ actually an xmlCharEncoding'/> parse the declaration for a Mixed Element content The leading '(' and spaces have been skipped in xmlParseElementContentDecl [47] children ::= (choice | seq) ('?' | '*' | '+')? [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')? [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')' [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' [ VC: Proper Group/PE Nesting ] applies to [49] and [50] TODO Parameter-entity replacement text must be properly nested with parenthesized groups. That is to say, if either of the opening or closing parentheses in a choice, seq, or Mixed construct is contained in the replacement text for a parameter entity, both must be contained in the same replacement text. For interoperability, if a parameter-entity reference appears in a choice, seq, or Mixed construct, its replacement text should not be empty, and neither the first nor last non-blank character of the replacement text should be a connector (| or ,). - + parse the declaration for an Element content either Mixed or Children, the cases EMPTY and ANY are handled directly in xmlParseElementDecl [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children @@ -7832,7 +7879,7 @@ actually an xmlCharEncoding'/> parse the declaration for a Mixed Element content The leading '(' and spaces have been skipped in xmlParseElementContentDecl [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')' [ VC: Proper Group/PE Nesting ] applies to [51] too (see [49]) [ VC: No Duplicate Types ] The same name must not appear more than once in a single mixed-content declaration. - + parse the XML encoding name [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* @@ -8106,6 +8153,13 @@ actually an xmlCharEncoding'/> + + Create a buffered parser input for the progressive parsing for the input from an immutable memory area. This will not copy the memory area to the buffer, but the memory is expected to be available until the end of the parsing, this is useful for example when using mmap'ed file. + + + + + Grow up the content of the input buffer, the old data are preserved This routine handle the I18N transcoding to internal UTF-8 This routine is used when operating the parser in normal (pull) mode TODO: one should be able to remove one extra copy by copying directly onto in->buffer or in->raw @@ -9490,6 +9544,36 @@ actually an xmlCharEncoding'/> + + The base URI of the node. + + + + + The local name of the node. + + + + + The qualified name of the node, equal to Prefix :LocalName. + + + + + The URI defining the namespace associated with the node. + + + + + A shorthand reference to the namespace associated with the node. + + + + + + + + Hacking interface allowing to get the xmlDocPtr correponding to the current document being accessed by the xmlTextReader. This is dangerous because the associated node may be destroyed on the next Reads. diff --git a/include/libxml/dict.h b/include/libxml/dict.h index 551a7d81..56e85656 100644 --- a/include/libxml/dict.h +++ b/include/libxml/dict.h @@ -47,6 +47,10 @@ XMLPUBFUN const xmlChar * XMLCALL xmlDictLookup (xmlDictPtr dict, const xmlChar *name, int len); +XMLPUBFUN const xmlChar * XMLCALL + xmlDictQLookup (xmlDictPtr dict, + const xmlChar *prefix, + const xmlChar *name); XMLPUBFUN int XMLCALL xmlDictOwns (xmlDictPtr dict, const xmlChar *str); diff --git a/include/libxml/xmlreader.h b/include/libxml/xmlreader.h index 2f9a4ceb..c8af21a2 100644 --- a/include/libxml/xmlreader.h +++ b/include/libxml/xmlreader.h @@ -88,8 +88,6 @@ XMLPUBFUN int XMLCALL */ XMLPUBFUN int XMLCALL xmlTextReaderAttributeCount(xmlTextReaderPtr reader); -XMLPUBFUN xmlChar * XMLCALL - xmlTextReaderBaseUri (xmlTextReaderPtr reader); XMLPUBFUN int XMLCALL xmlTextReaderDepth (xmlTextReaderPtr reader); XMLPUBFUN int XMLCALL @@ -100,25 +98,39 @@ XMLPUBFUN int XMLCALL xmlTextReaderIsDefault (xmlTextReaderPtr reader); XMLPUBFUN int XMLCALL xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderNodeType (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderQuoteChar (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderReadState (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderBaseUri (xmlTextReaderPtr reader); XMLPUBFUN xmlChar * XMLCALL xmlTextReaderLocalName (xmlTextReaderPtr reader); XMLPUBFUN xmlChar * XMLCALL xmlTextReaderName (xmlTextReaderPtr reader); XMLPUBFUN xmlChar * XMLCALL xmlTextReaderNamespaceUri(xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL - xmlTextReaderNodeType (xmlTextReaderPtr reader); XMLPUBFUN xmlChar * XMLCALL xmlTextReaderPrefix (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL - xmlTextReaderQuoteChar (xmlTextReaderPtr reader); -XMLPUBFUN xmlChar * XMLCALL - xmlTextReaderValue (xmlTextReaderPtr reader); XMLPUBFUN xmlChar * XMLCALL xmlTextReaderXmlLang (xmlTextReaderPtr reader); -XMLPUBFUN int XMLCALL - xmlTextReaderReadState (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderValue (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstBaseUri (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstLocalName (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstName (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstPrefix (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstXmlLang (xmlTextReaderPtr reader); /* * Methods of the XmlTextReader */ diff --git a/python/libxml2class.txt b/python/libxml2class.txt index 6a77cd19..639d4089 100644 --- a/python/libxml2class.txt +++ b/python/libxml2class.txt @@ -650,6 +650,12 @@ Class xmlTextReader(xmlTextReaderCore) AttributeCount() BaseUri() Close() + ConstBaseUri() + ConstLocalName() + ConstName() + ConstNamespaceUri() + ConstPrefix() + ConstXmlLang() CurrentDoc() CurrentNode() Depth() diff --git a/tree.c b/tree.c index 0e4a6f42..a65fda8c 100644 --- a/tree.c +++ b/tree.c @@ -3432,20 +3432,6 @@ xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { #ifdef DEBUG_TREE xmlGenericError(xmlGenericErrorContext, "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n"); -#endif - return(old); - } - if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlReplaceNode : Trying to replace attribute node with other node type\n"); -#endif - return(old); - } - if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n"); #endif return(old); } @@ -6420,7 +6406,7 @@ xmlBufferEmpty(xmlBufferPtr buf) { if (buf->content == NULL) return; buf->use = 0; if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) { - buf->content=""; + buf->content = ""; } else { memset(buf->content, 0, buf->size); } diff --git a/xmlIO.c b/xmlIO.c index ff7c7ade..88b5054d 100644 --- a/xmlIO.c +++ b/xmlIO.c @@ -2039,7 +2039,7 @@ xmlParserInputBufferCreateStatic(const char *mem, int size, return(NULL); } memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); - ret->buffer = xmlBufferCreateStatic(mem, size); + ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size); if (ret->buffer == NULL) { xmlFree(ret); return(NULL); diff --git a/xmlreader.c b/xmlreader.c index f325352b..6c52e1f3 100644 --- a/xmlreader.c +++ b/xmlreader.c @@ -135,6 +135,14 @@ struct _xmlTextReader { static const char *xmlTextReaderIsEmpty = "This element is empty"; +/** + * CONSTSTR: + * + * Macro used to return an interned string + */ +#define CONSTSTR(str) xmlDictLookup(reader->ctxt->dict, (str), -1) +#define CONSTQSTR(p, str) xmlDictQLookup(reader->ctxt->dict, (p), (str)) + /************************************************************************ * * * Our own version of the freeing routines as we recycle nodes * @@ -2447,6 +2455,37 @@ xmlTextReaderLocalName(xmlTextReaderPtr reader) { return(xmlStrdup(node->name)); } +/** + * xmlTextReaderConstLocalName: + * @reader: the xmlTextReaderPtr used + * + * The local name of the node. + * + * Returns the local name or NULL if not available, the + * string will be deallocated with the reader. + */ +const xmlChar * +xmlTextReaderConstLocalName(xmlTextReaderPtr reader) { + xmlNodePtr node; + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + if (node->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) node; + if (ns->prefix == NULL) + return(CONSTSTR(BAD_CAST "xmlns")); + else + return(ns->prefix); + } + if ((node->type != XML_ELEMENT_NODE) && + (node->type != XML_ATTRIBUTE_NODE)) + return(xmlTextReaderConstName(reader)); + return(node->name); +} + /** * xmlTextReaderName: * @reader: the xmlTextReaderPtr used @@ -2522,6 +2561,74 @@ xmlTextReaderName(xmlTextReaderPtr reader) { return(NULL); } +/** + * xmlTextReaderConstName: + * @reader: the xmlTextReaderPtr used + * + * The qualified name of the node, equal to Prefix :LocalName. + * + * Returns the local name or NULL if not available, the string is + * deallocated with the reader. + */ +const xmlChar * +xmlTextReaderConstName(xmlTextReaderPtr reader) { + xmlNodePtr node; + + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + switch (node->type) { + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + if ((node->ns == NULL) || + (node->ns->prefix == NULL)) + return(node->name); + return(CONSTQSTR(node->ns->prefix, node->name)); + case XML_TEXT_NODE: + return(CONSTSTR(BAD_CAST "#text")); + case XML_CDATA_SECTION_NODE: + return(CONSTSTR(BAD_CAST "#cdata-section")); + case XML_ENTITY_NODE: + case XML_ENTITY_REF_NODE: + return(CONSTSTR(node->name)); + case XML_PI_NODE: + return(CONSTSTR(node->name)); + case XML_COMMENT_NODE: + return(CONSTSTR(BAD_CAST "#comment")); + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + return(CONSTSTR(BAD_CAST "#document")); + case XML_DOCUMENT_FRAG_NODE: + return(CONSTSTR(BAD_CAST "#document-fragment")); + case XML_NOTATION_NODE: + return(CONSTSTR(node->name)); + case XML_DOCUMENT_TYPE_NODE: + case XML_DTD_NODE: + return(CONSTSTR(node->name)); + case XML_NAMESPACE_DECL: { + xmlNsPtr ns = (xmlNsPtr) node; + + if (ns->prefix == NULL) + return(CONSTSTR(BAD_CAST "xmlns")); + return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix)); + } + + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + return(NULL); + } + return(NULL); +} + /** * xmlTextReaderPrefix: * @reader: the xmlTextReaderPtr used @@ -2553,6 +2660,38 @@ xmlTextReaderPrefix(xmlTextReaderPtr reader) { return(NULL); } +/** + * xmlTextReaderConstPrefix: + * @reader: the xmlTextReaderPtr used + * + * A shorthand reference to the namespace associated with the node. + * + * Returns the prefix or NULL if not available, the string is deallocated + * with the reader. + */ +const xmlChar * +xmlTextReaderConstPrefix(xmlTextReaderPtr reader) { + xmlNodePtr node; + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + if (node->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) node; + if (ns->prefix == NULL) + return(NULL); + return(CONSTSTR(BAD_CAST "xmlns")); + } + if ((node->type != XML_ELEMENT_NODE) && + (node->type != XML_ATTRIBUTE_NODE)) + return(NULL); + if ((node->ns != NULL) && (node->ns->prefix != NULL)) + return(CONSTSTR(node->ns->prefix)); + return(NULL); +} + /** * xmlTextReaderNamespaceUri: * @reader: the xmlTextReaderPtr used @@ -2580,6 +2719,34 @@ xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) { return(NULL); } +/** + * xmlTextReaderConstNamespaceUri: + * @reader: the xmlTextReaderPtr used + * + * The URI defining the namespace associated with the node. + * + * Returns the namespace URI or NULL if not available, the string + * will be deallocated with the reader + */ +const xmlChar * +xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) { + xmlNodePtr node; + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + if (node->type == XML_NAMESPACE_DECL) + return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/")); + if ((node->type != XML_ELEMENT_NODE) && + (node->type != XML_ATTRIBUTE_NODE)) + return(NULL); + if (node->ns != NULL) + return(CONSTSTR(node->ns->href)); + return(NULL); +} + /** * xmlTextReaderBaseUri: * @reader: the xmlTextReaderPtr used @@ -2595,6 +2762,30 @@ xmlTextReaderBaseUri(xmlTextReaderPtr reader) { return(xmlNodeGetBase(NULL, reader->node)); } +/** + * xmlTextReaderConstBaseUri: + * @reader: the xmlTextReaderPtr used + * + * The base URI of the node. + * + * Returns the base URI or NULL if not available, the string + * will be deallocated with the reader + */ +const xmlChar * +xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) { + xmlChar *tmp; + const xmlChar *ret; + + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + tmp = xmlNodeGetBase(NULL, reader->node); + if (tmp == NULL) + return(NULL); + ret = CONSTSTR(tmp); + xmlFree(tmp); + return(ret); +} + /** * xmlTextReaderDepth: * @reader: the xmlTextReaderPtr used @@ -2775,6 +2966,31 @@ xmlTextReaderXmlLang(xmlTextReaderPtr reader) { return(xmlNodeGetLang(reader->node)); } +/** + * xmlTextReaderXmlLang: + * @reader: the xmlTextReaderPtr used + * + * The xml:lang scope within which the node resides. + * + * Returns the xml:lang value or NULL if none exists. + */ +const xmlChar * +xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) { + xmlChar *tmp; + const xmlChar *ret; + + if (reader == NULL) + return(NULL); + if (reader->node == NULL) + return(NULL); + tmp = xmlNodeGetLang(reader->node); + if (tmp == NULL) + return(NULL); + ret = CONSTSTR(tmp); + xmlFree(tmp); + return(ret); +} + /** * xmlTextReaderNormalization: * @reader: the xmlTextReaderPtr used