adding namespace checkings while making sure they still parse as
* parser.c parserInternals.c tree.c include/libxml/parser.h
include/libxml/xmlerror.h: adding namespace checkings
while making sure they still parse as wellformed documents.
Add an nsWellFormed status report to the context, and
provide new appropriate error codes.
* Makefile.am result/namespaces/* test/namespaces/*: add
specific regression testing for the new namespace support
* test/att5 result/noent/att5 result/att5 result/att5.sax:
add more coverage for the attribute parsing and normalization
code.
Daniel
diff --git a/ChangeLog b/ChangeLog
index c756cf0..5b908ca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+Fri Sep 12 01:36:20 CEST 2003 Daniel Veillard <daniel@veillard.com>
+
+ * parser.c parserInternals.c tree.c include/libxml/parser.h
+ include/libxml/xmlerror.h: adding namespace checkings
+ while making sure they still parse as wellformed documents.
+ Add an nsWellFormed status report to the context, and
+ provide new appropriate error codes.
+ * Makefile.am result/namespaces/* test/namespaces/*: add
+ specific regression testing for the new namespace support
+ * test/att5 result/noent/att5 result/att5 result/att5.sax:
+ add more coverage for the attribute parsing and normalization
+ code.
+
Fri Sep 12 01:34:19 CEST 2003 Daniel Veillard <daniel@veillard.com>
* threads.c: backport of a thread bugfix from 2_5_X branch
diff --git a/Makefile.am b/Makefile.am
index da1f38b..75b1f83 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -125,7 +125,7 @@
testall : tests SVGtests SAXtests
-tests: XMLtests XMLenttests SAXtests HTMLtests Validtests URItests XPathtests XPtrtests XIncludetests C14Ntests Scripttests Catatests @TEST_REGEXPS@ @TEST_SCHEMAS@ @TEST_THREADS@
+tests: XMLtests XMLenttests NStests SAXtests HTMLtests Validtests URItests XPathtests XPtrtests XIncludetests C14Ntests Scripttests Catatests @TEST_REGEXPS@ @TEST_SCHEMAS@ @TEST_THREADS@
@(if [ "@PYTHON_SUBDIR@" != "" ] ; then cd python ; $(MAKE) tests ; fi)
valgrind:
@@ -279,6 +279,29 @@
rm result.$$name result2.$$name ; \
fi ; fi ; done)
+NStests : xmllint$(EXEEXT)
+ @(echo > .memdump)
+ @echo "##"
+ @echo "## XML Namespaces regression tests"
+ @echo "##"
+ -@(for i in $(srcdir)/test/namespaces/* ; do \
+ name=`basename $$i`; \
+ if [ ! -d $$i ] ; then \
+ if [ ! -f $(srcdir)/result/namespaces/$$name ] ; then \
+ echo New test file $$name ; \
+ $(CHECKER) $(top_builddir)/xmllint $$i \
+ 2> $(srcdir)/result/namespaces/$$name.err \
+ > $(srcdir)/result/namespaces/$$name ; \
+ grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0"; \
+ else \
+ echo Testing $$name ; \
+ $(CHECKER) $(top_builddir)/xmllint $$i 2> error.$$name > result.$$name ; \
+ grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0"; \
+ diff $(srcdir)/result/namespaces/$$name result.$$name ; \
+ diff $(srcdir)/result/namespaces/$$name.err error.$$name ; \
+ rm result.$$name error.$$name ; \
+ fi ; fi ; done)
+
Docbtests : xmllint$(EXEEXT)
@(echo > .memdump)
@echo "##"
diff --git a/include/libxml/parser.h b/include/libxml/parser.h
index 967f3fd..7a0eaea 100644
--- a/include/libxml/parser.h
+++ b/include/libxml/parser.h
@@ -260,6 +260,7 @@
void * *pushTab; /* array of data for push */
xmlHashTablePtr attsDefault; /* defaulted attributes if any */
xmlHashTablePtr attsSpecial; /* non-CDATA attributes if any */
+ int nsWellFormed; /* is the document XML Nanespace okay */
};
/**
diff --git a/include/libxml/xmlerror.h b/include/libxml/xmlerror.h
index a71f327..2b74b1d 100644
--- a/include/libxml/xmlerror.h
+++ b/include/libxml/xmlerror.h
@@ -135,8 +135,12 @@
XML_ERR_INVALID_URI, /* 91 */
XML_ERR_URI_FRAGMENT, /* 92 */
XML_WAR_CATALOG_PI, /* 93 */
- XML_ERR_NO_DTD /* 94 */
-}xmlParserErrors;
+ XML_ERR_NO_DTD, /* 94 */
+ XML_NS_ERR_XML_NAMESPACE,
+ XML_NS_ERR_UNDEFINED_NAMESPACE,
+ XML_NS_ERR_QNAME,
+ XML_NS_ERR_ATTRIBUTE_REDEFINED
+} xmlParserErrors;
/**
* xmlGenericErrorFunc:
diff --git a/parser.c b/parser.c
index ddf4bd8..32607d1 100644
--- a/parser.c
+++ b/parser.c
@@ -7302,15 +7302,13 @@
GROW;
c = CUR_CHAR(l);
if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
- (!IS_LETTER(c) && (c != '_') &&
- (c != ':'))) {
+ (!IS_LETTER(c) && (c != '_'))) {
return(NULL);
}
while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
((IS_LETTER(c)) || (IS_DIGIT(c)) ||
- (c == '.') || (c == '-') ||
- (c == '_') || (c == ':') ||
+ (c == '.') || (c == '-') || (c == '_') ||
(IS_COMBINING(c)) ||
(IS_EXTENDER(c)))) {
if (count++ > 100) {
@@ -7423,24 +7421,64 @@
GROW;
l = xmlParseNCName(ctxt);
- if (l == NULL) return(NULL);
+ if (l == NULL) {
+ if (CUR == ':') {
+ l = xmlParseName(ctxt);
+ if (l != NULL) {
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) {
+ ctxt->sax->error(ctxt->userData,
+ "Failed to parse QName '%s'\n", l);
+ }
+ ctxt->nsWellFormed = 0;
+ ctxt->errNo = XML_NS_ERR_QNAME;
+ *prefix = NULL;
+ return(l);
+ }
+ }
+ return(NULL);
+ }
if (CUR == ':') {
NEXT;
p = l;
l = xmlParseNCName(ctxt);
if (l == NULL) {
+ xmlChar *tmp;
+
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) {
ctxt->sax->error(ctxt->userData,
"Failed to parse QName '%s:'\n", p);
}
- return(NULL);
+ ctxt->nsWellFormed = 0;
+ ctxt->errNo = XML_NS_ERR_QNAME;
+ tmp = xmlBuildQName(BAD_CAST "", p, NULL, 0);
+ p = xmlDictLookup(ctxt->dict, tmp, -1);
+ if (tmp != NULL) xmlFree(tmp);
+ *prefix = NULL;
+ return(p);
}
if (CUR == ':') {
+ xmlChar *tmp;
+
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) {
ctxt->sax->error(ctxt->userData,
"Failed to parse QName '%s:%s:'\n", p, l);
}
- return(NULL);
+ ctxt->nsWellFormed = 0;
+ ctxt->errNo = XML_NS_ERR_QNAME;
+ NEXT;
+ tmp = (xmlChar *) xmlParseName(ctxt);
+ if (tmp != NULL) {
+ tmp = xmlBuildQName(tmp, l, NULL, 0);
+ l = xmlDictLookup(ctxt->dict, tmp, -1);
+ if (tmp != NULL) xmlFree(tmp);
+ *prefix = p;
+ return(l);
+ }
+ tmp = xmlBuildQName(BAD_CAST "", l, NULL, 0);
+ l = xmlDictLookup(ctxt->dict, tmp, -1);
+ if (tmp != NULL) xmlFree(tmp);
+ *prefix = p;
+ return(l);
}
*prefix = p;
} else
@@ -7895,13 +7933,29 @@
const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len);
xmlURIPtr uri;
+ if (attname == ctxt->str_xml) {
+ if (URL != ctxt->str_xml_ns) {
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt->userData,
+ "xml namespace prefix mapped to wrong URI\n");
+ ctxt->nsWellFormed = 0;
+ }
+ ctxt->errNo = XML_NS_ERR_XML_NAMESPACE;
+ /*
+ * Do not keep a namespace definition node
+ */
+ if (alloc != 0) xmlFree(attvalue);
+ SKIP_BLANKS;
+ continue;
+ }
uri = xmlParseURI((const char *) URL);
if (uri == NULL) {
if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
ctxt->sax->warning(ctxt->userData,
- "xmlns:%s: %s not a valid URI\n", attname, URL);
+ "xmlns:%s: '%s' is not a valid URI\n",
+ attname, URL);
} else {
- if (uri->scheme == NULL) {
+ if ((ctxt->pedantic) && (uri->scheme == NULL)) {
if ((ctxt->sax != NULL) &&
(ctxt->sax->warning != NULL))
ctxt->sax->warning(ctxt->userData,
@@ -7985,8 +8039,10 @@
if ((atts[i + 1] != NULL) && (nsname == NULL)) {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
- "Namespace prefix %s for %s on %d is not defined\n",
+ "Namespace prefix %s for %s on %s is not defined\n",
atts[i + 1], atts[i], localname);
+ ctxt->nsWellFormed = 0;
+ ctxt->errNo = XML_NS_ERR_UNDEFINED_NAMESPACE;
}
atts[i + 2] = nsname;
/*
@@ -8015,8 +8071,10 @@
}
if ((nsname != NULL) && (atts[j + 2] == nsname)) {
ctxt->sax->error(ctxt->userData,
- "Attribute %s in %s redefined\n",
+ "Namespaced Attribute %s in '%s' redefined\n",
atts[i], nsname);
+ ctxt->nsWellFormed = 0;
+ ctxt->errNo = XML_NS_ERR_ATTRIBUTE_REDEFINED;
break;
}
}
@@ -8103,7 +8161,9 @@
if ((prefix != NULL) && (nsname == NULL)) {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
- "Namespace prefix %s on %d is not defined\n", prefix, localname);
+ "Namespace prefix %s on %s is not defined\n", prefix, localname);
+ ctxt->nsWellFormed = 0;
+ ctxt->errNo = XML_NS_ERR_UNDEFINED_NAMESPACE;
}
*pref = prefix;
*URI = nsname;
diff --git a/parserInternals.c b/parserInternals.c
index 8b7b515..9a71a7c 100644
--- a/parserInternals.c
+++ b/parserInternals.c
@@ -2309,6 +2309,7 @@
ctxt->userData = ctxt;
ctxt->myDoc = NULL;
ctxt->wellFormed = 1;
+ ctxt->nsWellFormed = 1;
ctxt->valid = 1;
ctxt->loadsubset = xmlLoadExtDtdDefaultValue;
ctxt->validate = xmlDoValidityCheckingDefaultValue;
diff --git a/result/att5 b/result/att5
new file mode 100644
index 0000000..8768e36
--- /dev/null
+++ b/result/att5
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ATTLIST normId attr NMTOKENS #IMPLIED>
+]>
+<doc>
+ <!-- no normalization -->
+ <norm attr=" "/>
+ <norm attr=" foo bar "/>
+ <norm attr=" foobar"/>
+ <norm attr=" foo bar "/>
+ <norm attr="foobar "/>
+ <norm attr=" & "/>
+ <norm attr=" foo&bar "/>
+ <norm attr=" foobar&"/>
+ <norm attr="&foo bar "/>
+ <norm attr="foobar &"/>
+ <norm attr=" < "/>
+ <norm attr=" foo<bar "/>
+ <norm attr=" foobar<"/>
+ <norm attr="<foo bar "/>
+ <norm attr="foobar <"/>
+ <norm attr=" 	 "/>
+ <!-- normalization -->
+ <normId attr=""/>
+ <normId attr="foo bar"/>
+ <normId attr="foobar"/>
+ <normId attr="foo bar"/>
+ <normId attr="foobar"/>
+ <normId attr="&"/>
+ <normId attr="foo&bar"/>
+ <normId attr="foobar&"/>
+ <normId attr="&foo bar"/>
+ <normId attr="foobar &"/>
+ <normId attr="<"/>
+ <normId attr="foo<bar"/>
+ <normId attr="foobar<"/>
+ <normId attr="<foo bar"/>
+ <normId attr="foobar <"/>
+ <normId attr=" 	"/> <!-- PBM serializing back -->
+</doc>
diff --git a/result/att5.sax b/result/att5.sax
new file mode 100644
index 0000000..ebd96f5
--- /dev/null
+++ b/result/att5.sax
@@ -0,0 +1,168 @@
+SAX.setDocumentLocator()
+SAX.startDocument()
+SAX.internalSubset(doc, , )
+SAX.attributeDecl(normId, attr, 8, 3, NULL, ...)
+SAX.externalSubset(doc, , )
+SAX.startElement(doc)
+SAX.characters(
+ , 3)
+SAX.comment( no normalization )
+SAX.characters(
+ , 3)
+SAX.startElement(norm, attr=' ')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.startElement(norm, attr=' foo bar ')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.startElement(norm, attr=' foobar')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.startElement(norm, attr=' foo bar ')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.startElement(norm, attr='foobar ')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.getEntity(amp)
+SAX.startElement(norm, attr=' & ')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.getEntity(amp)
+SAX.startElement(norm, attr=' foo&bar ')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.getEntity(amp)
+SAX.startElement(norm, attr=' foobar&')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.getEntity(amp)
+SAX.startElement(norm, attr='&foo bar ')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.getEntity(amp)
+SAX.startElement(norm, attr='foobar &')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.getEntity(lt)
+SAX.startElement(norm, attr=' < ')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.getEntity(lt)
+SAX.startElement(norm, attr=' foo<bar ')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.getEntity(lt)
+SAX.startElement(norm, attr=' foobar<')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.getEntity(lt)
+SAX.startElement(norm, attr='<foo bar ')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.getEntity(lt)
+SAX.startElement(norm, attr='foobar <')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.startElement(norm, attr='
+ ')
+SAX.endElement(norm)
+SAX.characters(
+ , 3)
+SAX.comment( normalization )
+SAX.characters(
+ , 3)
+SAX.startElement(normId, attr=' ')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.startElement(normId, attr=' foo bar ')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.startElement(normId, attr=' foobar')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.startElement(normId, attr=' foo bar ')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.startElement(normId, attr='foobar ')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.getEntity(amp)
+SAX.startElement(normId, attr=' & ')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.getEntity(amp)
+SAX.startElement(normId, attr=' foo&bar ')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.getEntity(amp)
+SAX.startElement(normId, attr=' foobar&')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.getEntity(amp)
+SAX.startElement(normId, attr='&foo bar ')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.getEntity(amp)
+SAX.startElement(normId, attr='foobar &')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.getEntity(lt)
+SAX.startElement(normId, attr=' < ')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.getEntity(lt)
+SAX.startElement(normId, attr=' foo<bar ')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.getEntity(lt)
+SAX.startElement(normId, attr=' foobar<')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.getEntity(lt)
+SAX.startElement(normId, attr='<foo bar ')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.getEntity(lt)
+SAX.startElement(normId, attr='foobar <')
+SAX.endElement(normId)
+SAX.characters(
+ , 3)
+SAX.startElement(normId, attr='
+ ')
+SAX.endElement(normId)
+SAX.characters( , 1)
+SAX.comment( PBM serializing back )
+SAX.characters(
+, 1)
+SAX.endElement(doc)
+SAX.endDocument()
diff --git a/result/namespaces/err_0.xml b/result/namespaces/err_0.xml
new file mode 100644
index 0000000..968d954
--- /dev/null
+++ b/result/namespaces/err_0.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<foo xmlnsbar="1"/>
diff --git a/result/namespaces/err_0.xml.err b/result/namespaces/err_0.xml.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/result/namespaces/err_0.xml.err
diff --git a/result/namespaces/err_1.xml b/result/namespaces/err_1.xml
new file mode 100644
index 0000000..a4aa8ff
--- /dev/null
+++ b/result/namespaces/err_1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<foo xmlns:="http://example.com/"/>
diff --git a/result/namespaces/err_1.xml.err b/result/namespaces/err_1.xml.err
new file mode 100644
index 0000000..3c3918f
--- /dev/null
+++ b/result/namespaces/err_1.xml.err
@@ -0,0 +1,3 @@
+./test/namespaces/err_1.xml:1: error: Failed to parse QName 'xmlns:'
+<foo xmlns:="http://example.com/"/>
+ ^
diff --git a/result/namespaces/err_2.xml b/result/namespaces/err_2.xml
new file mode 100644
index 0000000..73e727b
--- /dev/null
+++ b/result/namespaces/err_2.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<:/>
diff --git a/result/namespaces/err_2.xml.err b/result/namespaces/err_2.xml.err
new file mode 100644
index 0000000..2619eb5
--- /dev/null
+++ b/result/namespaces/err_2.xml.err
@@ -0,0 +1,3 @@
+./test/namespaces/err_2.xml:1: error: Failed to parse QName ':'
+<:/>
+ ^
diff --git a/result/namespaces/err_3.xml b/result/namespaces/err_3.xml
new file mode 100644
index 0000000..ee51834
--- /dev/null
+++ b/result/namespaces/err_3.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<:foo/>
diff --git a/result/namespaces/err_3.xml.err b/result/namespaces/err_3.xml.err
new file mode 100644
index 0000000..8a54afc
--- /dev/null
+++ b/result/namespaces/err_3.xml.err
@@ -0,0 +1,3 @@
+./test/namespaces/err_3.xml:1: error: Failed to parse QName ':foo'
+<:foo/>
+ ^
diff --git a/result/namespaces/err_4.xml b/result/namespaces/err_4.xml
new file mode 100644
index 0000000..d0d664e
--- /dev/null
+++ b/result/namespaces/err_4.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<f: xmlns:f="http://example.com/foo"/>
diff --git a/result/namespaces/err_4.xml.err b/result/namespaces/err_4.xml.err
new file mode 100644
index 0000000..1fdbccc
--- /dev/null
+++ b/result/namespaces/err_4.xml.err
@@ -0,0 +1,3 @@
+./test/namespaces/err_4.xml:1: error: Failed to parse QName 'f:'
+<f: xmlns:f="http://example.com/foo"/>
+ ^
diff --git a/result/namespaces/err_6.xml b/result/namespaces/err_6.xml
new file mode 100644
index 0000000..daa2a58
--- /dev/null
+++ b/result/namespaces/err_6.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<f:a:b xmlns:f="http://example.com/foo"/>
diff --git a/result/namespaces/err_6.xml.err b/result/namespaces/err_6.xml.err
new file mode 100644
index 0000000..0bdfd2c
--- /dev/null
+++ b/result/namespaces/err_6.xml.err
@@ -0,0 +1,3 @@
+./test/namespaces/err_6.xml:1: error: Failed to parse QName 'f:a:'
+<f:a:b xmlns:f="http://example.com/foo"/>
+ ^
diff --git a/result/namespaces/err_7.xml b/result/namespaces/err_7.xml
new file mode 100644
index 0000000..f4e5164
--- /dev/null
+++ b/result/namespaces/err_7.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<foo/>
diff --git a/result/namespaces/err_7.xml.err b/result/namespaces/err_7.xml.err
new file mode 100644
index 0000000..147fc3c
--- /dev/null
+++ b/result/namespaces/err_7.xml.err
@@ -0,0 +1,3 @@
+./test/namespaces/err_7.xml:1: error: Namespace prefix f on foo is not defined
+<f:foo/>
+ ^
diff --git a/result/namespaces/err_8.xml b/result/namespaces/err_8.xml
new file mode 100644
index 0000000..5608312
--- /dev/null
+++ b/result/namespaces/err_8.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<tst/>
diff --git a/result/namespaces/err_8.xml.err b/result/namespaces/err_8.xml.err
new file mode 100644
index 0000000..e5f4416
--- /dev/null
+++ b/result/namespaces/err_8.xml.err
@@ -0,0 +1,3 @@
+./test/namespaces/err_8.xml:1: error: xml namespace prefix mapped to wrong URI
+<tst xmlns:xml="http://example.com/"/>
+ ^
diff --git a/result/namespaces/err_9.xml b/result/namespaces/err_9.xml
new file mode 100644
index 0000000..0407dff
--- /dev/null
+++ b/result/namespaces/err_9.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<tst xmlns:a="http://example.com/" xmlns:b="http://example.com/" a:err="1" b:err="2"/>
diff --git a/result/namespaces/err_9.xml.err b/result/namespaces/err_9.xml.err
new file mode 100644
index 0000000..6a0d089
--- /dev/null
+++ b/result/namespaces/err_9.xml.err
@@ -0,0 +1,3 @@
+./test/namespaces/err_9.xml:2: error: Namespaced Attribute err in 'http://example.com/' redefined
+ a:err="1" b:err="2"/>
+ ^
diff --git a/result/noent/att5 b/result/noent/att5
new file mode 100644
index 0000000..8768e36
--- /dev/null
+++ b/result/noent/att5
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ATTLIST normId attr NMTOKENS #IMPLIED>
+]>
+<doc>
+ <!-- no normalization -->
+ <norm attr=" "/>
+ <norm attr=" foo bar "/>
+ <norm attr=" foobar"/>
+ <norm attr=" foo bar "/>
+ <norm attr="foobar "/>
+ <norm attr=" & "/>
+ <norm attr=" foo&bar "/>
+ <norm attr=" foobar&"/>
+ <norm attr="&foo bar "/>
+ <norm attr="foobar &"/>
+ <norm attr=" < "/>
+ <norm attr=" foo<bar "/>
+ <norm attr=" foobar<"/>
+ <norm attr="<foo bar "/>
+ <norm attr="foobar <"/>
+ <norm attr=" 	 "/>
+ <!-- normalization -->
+ <normId attr=""/>
+ <normId attr="foo bar"/>
+ <normId attr="foobar"/>
+ <normId attr="foo bar"/>
+ <normId attr="foobar"/>
+ <normId attr="&"/>
+ <normId attr="foo&bar"/>
+ <normId attr="foobar&"/>
+ <normId attr="&foo bar"/>
+ <normId attr="foobar &"/>
+ <normId attr="<"/>
+ <normId attr="foo<bar"/>
+ <normId attr="foobar<"/>
+ <normId attr="<foo bar"/>
+ <normId attr="foobar <"/>
+ <normId attr=" 	"/> <!-- PBM serializing back -->
+</doc>
diff --git a/test/att5 b/test/att5
new file mode 100644
index 0000000..2c05105
--- /dev/null
+++ b/test/att5
@@ -0,0 +1,73 @@
+<!DOCTYPE doc [<!ATTLIST normId attr NMTOKENS #IMPLIED>]>
+<doc>
+ <!-- no normalization -->
+ <norm attr=' '/>
+ <norm attr='
+ foo bar '/>
+ <norm attr='
+
+foobar'/>
+ <norm attr=' foo bar
+'/>
+ <norm attr='foobar
+
+'/>
+ <norm attr=' & '/>
+ <norm attr='
+ foo&bar '/>
+ <norm attr='
+
+foobar&'/>
+ <norm attr='&foo bar
+'/>
+ <norm attr='foobar
+
+&'/>
+ <norm attr=' < '/>
+ <norm attr='
+ foo<bar '/>
+ <norm attr='
+
+foobar<'/>
+ <norm attr='<foo bar
+'/>
+ <norm attr='foobar
+
+<'/>
+ <norm attr='   
	 '/>
+ <!-- normalization -->
+ <normId attr=' '/>
+ <normId attr='
+ foo bar '/>
+ <normId attr='
+
+foobar'/>
+ <normId attr=' foo bar
+'/>
+ <normId attr='foobar
+
+'/>
+ <normId attr=' & '/>
+ <normId attr='
+ foo&bar '/>
+ <normId attr='
+
+foobar&'/>
+ <normId attr='&foo bar
+'/>
+ <normId attr='foobar
+
+&'/>
+ <normId attr=' < '/>
+ <normId attr='
+ foo<bar '/>
+ <normId attr='
+
+foobar<'/>
+ <normId attr='<foo bar
+'/>
+ <normId attr='foobar
+
+<'/>
+ <normId attr=' 
	 '/> <!-- PBM serializing back -->
+</doc>
diff --git a/test/namespaces/err_0.xml b/test/namespaces/err_0.xml
new file mode 100644
index 0000000..50bdd32
--- /dev/null
+++ b/test/namespaces/err_0.xml
@@ -0,0 +1 @@
+<foo xmlnsbar="1"/>
diff --git a/test/namespaces/err_1.xml b/test/namespaces/err_1.xml
new file mode 100644
index 0000000..eb6f43b
--- /dev/null
+++ b/test/namespaces/err_1.xml
@@ -0,0 +1 @@
+<foo xmlns:="http://example.com/"/>
diff --git a/test/namespaces/err_2.xml b/test/namespaces/err_2.xml
new file mode 100644
index 0000000..9fd51b3
--- /dev/null
+++ b/test/namespaces/err_2.xml
@@ -0,0 +1 @@
+<:/>
diff --git a/test/namespaces/err_3.xml b/test/namespaces/err_3.xml
new file mode 100644
index 0000000..3d4d439
--- /dev/null
+++ b/test/namespaces/err_3.xml
@@ -0,0 +1 @@
+<:foo/>
diff --git a/test/namespaces/err_4.xml b/test/namespaces/err_4.xml
new file mode 100644
index 0000000..9dc294e
--- /dev/null
+++ b/test/namespaces/err_4.xml
@@ -0,0 +1 @@
+<f: xmlns:f="http://example.com/foo"/>
diff --git a/test/namespaces/err_5.xml b/test/namespaces/err_5.xml
new file mode 100644
index 0000000..5943c11
--- /dev/null
+++ b/test/namespaces/err_5.xml
@@ -0,0 +1 @@
+<f:a: xmlns:f="http://example.com/foo"/>
diff --git a/test/namespaces/err_6.xml b/test/namespaces/err_6.xml
new file mode 100644
index 0000000..e3eb3b2
--- /dev/null
+++ b/test/namespaces/err_6.xml
@@ -0,0 +1 @@
+<f:a:b xmlns:f="http://example.com/foo"/>
diff --git a/test/namespaces/err_7.xml b/test/namespaces/err_7.xml
new file mode 100644
index 0000000..5bbe235
--- /dev/null
+++ b/test/namespaces/err_7.xml
@@ -0,0 +1 @@
+<f:foo/>
diff --git a/test/namespaces/err_8.xml b/test/namespaces/err_8.xml
new file mode 100644
index 0000000..8321da2
--- /dev/null
+++ b/test/namespaces/err_8.xml
@@ -0,0 +1 @@
+<tst xmlns:xml="http://example.com/"/>
diff --git a/test/namespaces/err_9.xml b/test/namespaces/err_9.xml
new file mode 100644
index 0000000..4478c60
--- /dev/null
+++ b/test/namespaces/err_9.xml
@@ -0,0 +1,2 @@
+<tst xmlns:a="http://example.com/" xmlns:b="http://example.com/"
+ a:err="1" b:err="2"/>
diff --git a/tree.c b/tree.c
index a68beb9..ba3cbf2 100644
--- a/tree.c
+++ b/tree.c
@@ -151,8 +151,8 @@
int lenn, lenp;
xmlChar *ret;
- if ((ncname == NULL) || (*ncname == 0)) return(NULL);
- if ((prefix == NULL) || (*prefix == 0)) return((xmlChar *) ncname);
+ if (ncname == NULL) return(NULL);
+ if (prefix == NULL) return((xmlChar *) ncname);
lenn = strlen((char *) ncname);
lenp = strlen((char *) prefix);