allow to inherit attributes from the DTD directly in the tree, this is

* SAX.c testXPath.c valid.c xmllint.c include/libxml/valid.h:
  allow to inherit attributes from the DTD directly in the
  tree, this is needed for XPath and can be a useful feature.
  Inherited namespaces are always provided at the tree level now
* test/defattr* result/defattr* result/noent/defattr*: added a couple
  of tests for this feature (XSLT being the prime user).
Daniel
diff --git a/ChangeLog b/ChangeLog
index 4dfea66..4b92af4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Tue Aug  7 03:05:58 CEST 2001 Daniel Veillard <daniel@veillard.com>
+
+	* SAX.c testXPath.c valid.c xmllint.c include/libxml/valid.h:
+	  allow to inherit attributes from the DTD directly in the
+	  tree, this is needed for XPath and can be a useful feature.
+	  Inherited namespaces are always provided at the tree level now
+	* test/defattr* result/defattr* result/noent/defattr*: added a couple
+	  of tests for this feature (XSLT being the prime user).
+
 Fri Aug  3 14:02:20 CEST 2001 Daniel Veillard <daniel@veillard.com>
 
 	* DOCBparser.c Makefile.am nanohttp.c parser.c testHTML.c
diff --git a/SAX.c b/SAX.c
index beac21e..86e95d7 100644
--- a/SAX.c
+++ b/SAX.c
@@ -21,6 +21,7 @@
 #include <libxml/xmlIO.h>
 #include <libxml/SAX.h>
 #include <libxml/uri.h>
+#include <libxml/valid.h>
 #include <libxml/HTMLtree.h>
 
 /* #define DEBUG_SAX */
@@ -1033,6 +1034,78 @@
     }
 
     /*
+     * Insert all the defaulted attributes from the DTD especially namespaces
+     */
+    if ((!ctxt->html) &&
+	((ctxt->myDoc->intSubset != NULL) ||
+	 (ctxt->myDoc->extSubset != NULL))) {
+	xmlElementPtr elemDecl = NULL;
+
+	if (prefix != NULL) {
+	    if (ctxt->myDoc->intSubset != NULL)
+		elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->intSubset,
+			                         name, prefix);
+	    if ((elemDecl == NULL) && (ctxt->myDoc->extSubset != NULL))
+		elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->extSubset,
+			                         name, prefix);
+	} else {
+	    if (ctxt->myDoc->intSubset != NULL)
+		elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->intSubset,
+			                         name, prefix);
+	    if ((elemDecl == NULL) && (ctxt->myDoc->extSubset != NULL))
+		elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->extSubset,
+			                         name, prefix);
+	}
+	if (elemDecl != NULL) {
+	    xmlAttributePtr  attr = elemDecl->attributes;
+	    while (attr != NULL) {
+		if (attr->defaultValue != NULL) {
+		    /*
+		     * the element should be instanciated in the tree if:
+		     *  - this is a namespace prefix
+		     *  - the user required for completion in the tree
+		     *    like XSLT
+		     */
+		    if (((attr->prefix != NULL) &&
+			 (xmlStrEqual(attr->prefix, BAD_CAST "xmlns"))) ||
+		        ((attr->prefix == NULL) &&
+			 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) ||
+			(ctxt->loadsubset & XML_COMPLETE_ATTRS)) {
+			xmlChar buffer[100];
+			const xmlChar *fulln = attr->name;
+
+			if (attr->prefix != NULL) {
+			    snprintf((char *) buffer, 99, "%s:%s",
+				     attr->prefix, attr->name);
+			    buffer[99] = 0;
+			    fulln = buffer;
+			}
+
+			/*
+			 * Check that the attribute is not declared in the
+			 * serialization
+			 */
+			att = NULL;
+			if (atts != NULL) {
+			    i = 0;
+			    att = atts[i];
+			    while (att != NULL) {
+				if (xmlStrEqual(att, fulln))
+				    break;
+				i += 2;
+				att = atts[i];
+			    }
+			}
+			if (att == NULL)
+			    attribute(ctxt, fulln, attr->defaultValue);
+		    }
+		}
+		attr = attr->nexth;
+	    }
+	}
+    }
+
+    /*
      * process all the attributes whose name start with "xml"
      */
     if (atts != NULL) {
diff --git a/include/libxml/valid.h b/include/libxml/valid.h
index 5b29e8d..276a2e4 100644
--- a/include/libxml/valid.h
+++ b/include/libxml/valid.h
@@ -230,8 +230,15 @@
 xmlAttributePtr	xmlGetDtdAttrDesc	(xmlDtdPtr dtd,
 					 const xmlChar *elem,
 					 const xmlChar *name);
+xmlAttributePtr	xmlGetDtdQAttrDesc	(xmlDtdPtr dtd,
+					 const xmlChar *elem,
+					 const xmlChar *name,
+					 const xmlChar *prefix);
 xmlNotationPtr	xmlGetDtdNotationDesc	(xmlDtdPtr dtd,
 					 const xmlChar *name);
+xmlElementPtr	xmlGetDtdQElementDesc	(xmlDtdPtr dtd,
+					 const xmlChar *name,
+					 const xmlChar *prefix);
 xmlElementPtr	xmlGetDtdElementDesc	(xmlDtdPtr dtd,
 					 const xmlChar *name);
 
diff --git a/result/defattr.xml b/result/defattr.xml
new file mode 100644
index 0000000..0a4ac15
--- /dev/null
+++ b/result/defattr.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ELEMENT doc EMPTY>
+<!ATTLIST doc xmlns CDATA #FIXED "http://www.example.com/">
+]>
+<doc xmlns="http://www.example.com/"/>
diff --git a/result/defattr2.xml b/result/defattr2.xml
new file mode 100644
index 0000000..8d1fc3b
--- /dev/null
+++ b/result/defattr2.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ELEMENT doc EMPTY>
+<!ATTLIST doc defatt (0 | 1) "0">
+<!ATTLIST doc xmlns:tst CDATA #FIXED "http://example.org">
+<!ATTLIST doc tst:att (0 | 1) "1">
+]>
+<doc xmlns:tst="http://example.org" att="1"/>
diff --git a/result/noent/defattr.xml b/result/noent/defattr.xml
new file mode 100644
index 0000000..0a4ac15
--- /dev/null
+++ b/result/noent/defattr.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ELEMENT doc EMPTY>
+<!ATTLIST doc xmlns CDATA #FIXED "http://www.example.com/">
+]>
+<doc xmlns="http://www.example.com/"/>
diff --git a/result/noent/defattr2.xml b/result/noent/defattr2.xml
new file mode 100644
index 0000000..8d1fc3b
--- /dev/null
+++ b/result/noent/defattr2.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ELEMENT doc EMPTY>
+<!ATTLIST doc defatt (0 | 1) "0">
+<!ATTLIST doc xmlns:tst CDATA #FIXED "http://example.org">
+<!ATTLIST doc tst:att (0 | 1) "1">
+]>
+<doc xmlns:tst="http://example.org" att="1"/>
diff --git a/test/defattr.xml b/test/defattr.xml
new file mode 100644
index 0000000..3f16a50
--- /dev/null
+++ b/test/defattr.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc EMPTY>
+<!ATTLIST doc
+     xmlns CDATA #FIXED "http://www.example.com/">
+]>
+<doc/>
diff --git a/test/defattr2.xml b/test/defattr2.xml
new file mode 100644
index 0000000..ab50709
--- /dev/null
+++ b/test/defattr2.xml
@@ -0,0 +1,8 @@
+<!DOCTYPE doc [
+<!ELEMENT doc EMPTY>
+<!ATTLIST doc
+     defatt  (0|1)   "0"
+     xmlns:tst CDATA #FIXED "http://example.org"
+     tst:att (0|1)   "1">
+]>
+<doc att="1"/>
diff --git a/testXPath.c b/testXPath.c
index 983299d..04d09d2 100644
--- a/testXPath.c
+++ b/testXPath.c
@@ -175,6 +175,8 @@
 	    usefile++;
     }
     if (valid != 0) xmlDoValidityCheckingDefaultValue = 1;
+    xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
+    xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
     if (nocdata != 0) {
 	xmlDefaultSAXHandlerInit();
 	xmlDefaultSAXHandler.cdataBlock = NULL;
diff --git a/valid.c b/valid.c
index a0e9c0f..df25a70 100644
--- a/valid.c
+++ b/valid.c
@@ -1271,13 +1271,40 @@
      */
     elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
     if (elemDef != NULL) {
+
         if ((type == XML_ATTRIBUTE_ID) &&
 	    (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
 	    VERROR(ctxt->userData, 
 	   "Element %s has too may ID attributes defined : %s\n",
 		   elem, name);
-        ret->nexth = elemDef->attributes;
-        elemDef->attributes = ret;
+	/*
+	 * Insert namespace default def first they need to be
+	 * processed firt.
+	 */
+	if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
+	    ((ret->prefix != NULL &&
+	     (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
+	    ret->nexth = elemDef->attributes;
+	    elemDef->attributes = ret;
+	} else {
+	    xmlAttributePtr tmp = elemDef->attributes;
+
+	    while ((tmp != NULL) &&
+		   ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
+		    ((ret->prefix != NULL &&
+		     (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
+		if (tmp->nexth == NULL)
+		    break;
+		tmp = tmp->nexth;
+	    }
+	    if (tmp != NULL) {
+		ret->nexth = tmp->nexth;
+	        tmp->nexth = ret;
+	    } else {
+		ret->nexth = elemDef->attributes;
+		elemDef->attributes = ret;
+	    }
+	}
     }
 
     /*
@@ -2280,7 +2307,7 @@
  * returns the xmlElementPtr if found or NULL
  */
 
-static xmlElementPtr
+xmlElementPtr
 xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
 	              const xmlChar *prefix) {
     xmlElementTablePtr table;
@@ -2341,7 +2368,7 @@
  * returns the xmlAttributePtr if found or NULL
  */
 
-static xmlAttributePtr
+xmlAttributePtr
 xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
 	          const xmlChar *prefix) {
     xmlAttributeTablePtr table;
diff --git a/xmllint.c b/xmllint.c
index ee020df..6573c3c 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -97,6 +97,7 @@
 #ifdef LIBXML_XINCLUDE_ENABLED
 static int xinclude = 0;
 #endif
+static int dtdattrs = 0;
 static int loaddtd = 0;
 static int progresult = 0;
 static int timing = 0;
@@ -792,8 +793,9 @@
     printf("\t--auto : generate a small doc on the fly\n");
 #ifdef LIBXML_XINCLUDE_ENABLED
     printf("\t--xinclude : do XInclude processing\n");
-    printf("\t--loaddtd : fetch external Dtd\n");
 #endif
+    printf("\t--loaddtd : fetch external Dtd\n");
+    printf("\t--dtdattr : loaddtd + populate the tree with inherited attributes \n");
 }
 int
 main(int argc, char **argv) {
@@ -850,7 +852,11 @@
 	else if ((!strcmp(argv[i], "-loaddtd")) ||
 	         (!strcmp(argv[i], "--loaddtd")))
 	    loaddtd++;
-	else if ((!strcmp(argv[i], "-valid")) ||
+	else if ((!strcmp(argv[i], "-dtdattr")) ||
+	         (!strcmp(argv[i], "--dtdattr"))) {
+	    loaddtd++;
+	    dtdattrs++;
+	} else if ((!strcmp(argv[i], "-valid")) ||
 	         (!strcmp(argv[i], "--valid")))
 	    valid++;
 	else if ((!strcmp(argv[i], "-postvalid")) ||
@@ -946,7 +952,10 @@
 	}
     }
     xmlLineNumbersDefault(1);
-    if (loaddtd != 0) xmlLoadExtDtdDefaultValue = 6; /* fetch DTDs by default */
+    if (loaddtd != 0)
+	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
+    if (dtdattrs)
+	xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS;
     if (noent != 0) xmlSubstituteEntitiesDefault(1);
     if (valid != 0) xmlDoValidityCheckingDefaultValue = 1;
     if ((htmlout) && (!nowrap)) {