fixed bug #92518 validation error were not covering namespace
* SAX.c valid.c include/libxml/valid.h: fixed bug #92518 validation
error were not covering namespace declarations.
* result/valid/dia.xml test/valid/dia.xml: the test wasn't valid,
it was missing the attribute declaration for the namespace
* result/VC/NS3: the fix now report breakages in that test
Daniel
diff --git a/ChangeLog b/ChangeLog
index 77e68ed..441a0a1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Thu Sep 26 17:33:46 CEST 2002 Daniel Veillard <daniel@veillard.com>
+
+ * SAX.c valid.c include/libxml/valid.h: fixed bug #92518 validation
+ error were not covering namespace declarations.
+ * result/valid/dia.xml test/valid/dia.xml: the test wasn't valid,
+ it was missing the attribute declaration for the namespace
+ * result/VC/NS3: the fix now report breakages in that test
+
Thu Sep 26 14:39:07 CEST 2002 Daniel Veillard <daniel@veillard.com>
* HTMLtree.c: fixing bug #94241 on HTML boolean attributes
diff --git a/SAX.c b/SAX.c
index 9cf06a0..c8452eb 100644
--- a/SAX.c
+++ b/SAX.c
@@ -795,18 +795,20 @@
}
/**
- * attribute:
+ * my_attribute:
* @ctx: the user data (XML parser context)
* @fullname: The attribute name, including namespace prefix
* @value: The attribute value
+ * @prefix: the prefix on the element node
*
* Handle an attribute that has been read by the parser.
* The default handling is to convert the attribute into an
* DOM subtree and past it in a new xmlAttr element added to
* the element.
*/
-void
-attribute(void *ctx, const xmlChar *fullname, const xmlChar *value)
+static void
+my_attribute(void *ctx, const xmlChar *fullname, const xmlChar *value,
+ const xmlChar *prefix)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlAttrPtr ret;
@@ -847,6 +849,8 @@
if ((!ctxt->html) && (ns == NULL) &&
(name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
(name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
+ xmlNsPtr nsret;
+
if (value[0] != 0) {
xmlURIPtr uri;
@@ -866,7 +870,16 @@
}
/* a default namespace definition */
- xmlNewNs(ctxt->node, value, NULL);
+ nsret = xmlNewNs(ctxt->node, value, NULL);
+
+ /*
+ * Validate also for namespace decls, they are attributes from
+ * an XML-1.0 perspective
+ */
+ if (nsret != NULL && ctxt->validate && ctxt->wellFormed &&
+ ctxt->myDoc && ctxt->myDoc->intSubset)
+ ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
+ ctxt->node, prefix, nsret, value);
if (name != NULL)
xmlFree(name);
if (nval != NULL)
@@ -876,23 +889,24 @@
if ((!ctxt->html) &&
(ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
(ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
- /*
- * Validate also for namespace decls, they are attributes from
- * an XML-1.0 perspective
- TODO ... doesn't map well with current API
- if (ctxt->validate && ctxt->wellFormed &&
- ctxt->myDoc && ctxt->myDoc->intSubset)
- ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
- ctxt->node, ret, value);
- */
+ xmlNsPtr nsret;
+
if (value[0] == 0) {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"Empty namespace name for prefix %s\n", name);
}
/* a standard namespace definition */
- xmlNewNs(ctxt->node, value, name);
+ nsret = xmlNewNs(ctxt->node, value, name);
xmlFree(ns);
+ /*
+ * Validate also for namespace decls, they are attributes from
+ * an XML-1.0 perspective
+ */
+ if (nsret != NULL && ctxt->validate && ctxt->wellFormed &&
+ ctxt->myDoc && ctxt->myDoc->intSubset)
+ ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
+ ctxt->node, prefix, nsret, value);
if (name != NULL)
xmlFree(name);
if (nval != NULL)
@@ -988,6 +1002,23 @@
xmlFree(ns);
}
+/**
+ * attribute:
+ * @ctx: the user data (XML parser context)
+ * @fullname: The attribute name, including namespace prefix
+ * @value: The attribute value
+ *
+ * Handle an attribute that has been read by the parser.
+ * The default handling is to convert the attribute into an
+ * DOM subtree and past it in a new xmlAttr element added to
+ * the element.
+ */
+void
+attribute(void *ctx, const xmlChar *fullname, const xmlChar *value)
+{
+ my_attribute(ctx, fullname, value, NULL);
+}
+
/*
* xmlCheckDefaultedAttributes:
*
@@ -1256,7 +1287,7 @@
while ((att != NULL) && (value != NULL)) {
if ((att[0] == 'x') && (att[1] == 'm') && (att[2] == 'l') &&
(att[3] == 'n') && (att[4] == 's'))
- attribute(ctxt, att, value);
+ my_attribute(ctxt, att, value, prefix);
att = atts[i++];
value = atts[i++];
diff --git a/include/libxml/valid.h b/include/libxml/valid.h
index 5535dd9..4cc5f97 100644
--- a/include/libxml/valid.h
+++ b/include/libxml/valid.h
@@ -264,6 +264,12 @@
xmlNodePtr elem,
xmlAttrPtr attr,
const xmlChar *value);
+int xmlValidateOneNamespace (xmlValidCtxtPtr ctxt,
+ xmlDocPtr doc,
+ xmlNodePtr elem,
+ const xmlChar *prefix,
+ xmlNsPtr ns,
+ const xmlChar *value);
int xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt,
xmlDocPtr doc);
int xmlValidateNotationUse (xmlValidCtxtPtr ctxt,
diff --git a/result/VC/NS3 b/result/VC/NS3
index 3e8cb74..4868dc5 100644
--- a/result/VC/NS3
+++ b/result/VC/NS3
@@ -1,3 +1,9 @@
+./test/VC/NS3:9: validity error: Value for attribute xmlns of foo is different from default "http://example.com/fooo"
+xmlns="http://example.com/foo" xmlns:foo="http://example.com/fo" foo:info="toto
+ ^
+./test/VC/NS3:9: validity error: Value for attribute xmlns of foo must be "http://example.com/fooo"
+xmlns="http://example.com/foo" xmlns:foo="http://example.com/fo" foo:info="toto
+ ^
./test/VC/NS3:9: validity error: Element foo namespace name for default namespace does not match the DTD
mlns="http://example.com/foo" xmlns:foo="http://example.com/fo" foo:info="toto"
^
diff --git a/result/valid/dia.xml b/result/valid/dia.xml
index 12282be..01e3253 100644
--- a/result/valid/dia.xml
+++ b/result/valid/dia.xml
@@ -1,6 +1,7 @@
<?xml version="1.0"?>
<!DOCTYPE dia:diagram [
<!ELEMENT dia:diagram (dia:diagramdata , dia:layer*)>
+<!ATTLIST dia:diagram xmlns:dia CDATA #FIXED "http://www.lysator.liu.se/~alla/dia/">
<!ELEMENT dia:diagramdata (dia:attribute)*>
<!ELEMENT dia:layer (dia:object | dia:group)*>
<!ATTLIST dia:layer dia:name CDATA #REQUIRED>
diff --git a/test/valid/dia.xml b/test/valid/dia.xml
index b6441ab..3ab3d06 100644
--- a/test/valid/dia.xml
+++ b/test/valid/dia.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!DOCTYPE dia:diagram [
<!ELEMENT dia:diagram (dia:diagramdata, (dia:layer)*) >
+<!ATTLIST dia:diagram
+ xmlns:dia CDATA #FIXED "http://www.lysator.liu.se/~alla/dia/">
+
<!ELEMENT dia:diagramdata (dia:attribute)* >
diff --git a/valid.c b/valid.c
index 9ebdbf5..58ab756 100644
--- a/valid.c
+++ b/valid.c
@@ -3817,6 +3817,232 @@
return(ret);
}
+/**
+ * xmlValidateOneNamespace:
+ * @ctxt: the validation context
+ * @doc: a document instance
+ * @elem: an element instance
+ * @ns: an namespace declaration instance
+ * @value: the attribute value (without entities processing)
+ *
+ * Try to validate a single namespace declaration for an element
+ * basically it does the following checks as described by the
+ * XML-1.0 recommendation:
+ * - [ VC: Attribute Value Type ]
+ * - [ VC: Fixed Attribute Default ]
+ * - [ VC: Entity Name ]
+ * - [ VC: Name Token ]
+ * - [ VC: ID ]
+ * - [ VC: IDREF ]
+ * - [ VC: Entity Name ]
+ * - [ VC: Notation Attributes ]
+ *
+ * The ID/IDREF uniqueness and matching are done separately
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
+ /* xmlElementPtr elemDecl; */
+ xmlAttributePtr attrDecl = NULL;
+ int val;
+ int ret = 1;
+
+ CHECK_DTD;
+ if ((elem == NULL) || (elem->name == NULL)) return(0);
+ if ((ns == NULL) || (ns->href == NULL)) return(0);
+
+ if (prefix != NULL) {
+ xmlChar qname[500];
+ snprintf((char *) qname, sizeof(qname), "%s:%s",
+ prefix, elem->name);
+ qname[sizeof(qname) - 1] = 0;
+ if (ns->prefix != NULL) {
+ attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
+ ns->prefix, BAD_CAST "xmlns");
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))
+ attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
+ ns->prefix, BAD_CAST "xmlns");
+ } else {
+ attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname,
+ BAD_CAST "xmlns");
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))
+ attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname,
+ BAD_CAST "xmlns");
+ }
+ }
+ if (attrDecl == NULL) {
+ if (ns->prefix != NULL) {
+ attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
+ ns->prefix, BAD_CAST "xmlns");
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))
+ attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
+ ns->prefix, BAD_CAST "xmlns");
+ } else {
+ attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
+ elem->name, BAD_CAST "xmlns");
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))
+ attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
+ elem->name, BAD_CAST "xmlns");
+ }
+ }
+
+
+ /* Validity Constraint: Attribute Value Type */
+ if (attrDecl == NULL) {
+ VECTXT(ctxt, elem);
+ if (ns->prefix != NULL) {
+ VERROR(ctxt->userData,
+ "No declaration for attribute xmlns:%s of element %s\n",
+ ns->prefix, elem->name);
+ } else {
+ VERROR(ctxt->userData,
+ "No declaration for attribute xmlns of element %s\n",
+ elem->name);
+ }
+ return(0);
+ }
+
+ val = xmlValidateAttributeValue(attrDecl->atype, value);
+ if (val == 0) {
+ VECTXT(ctxt, elem);
+ if (ns->prefix != NULL) {
+ VERROR(ctxt->userData,
+ "Syntax of value for attribute xmlns:%s of %s is not valid\n",
+ ns->prefix, elem->name);
+ } else {
+ VERROR(ctxt->userData,
+ "Syntax of value for attribute xmlns of %s is not valid\n",
+ elem->name);
+ }
+ ret = 0;
+ }
+
+ /* Validity constraint: Fixed Attribute Default */
+ if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
+ if (!xmlStrEqual(value, attrDecl->defaultValue)) {
+ VECTXT(ctxt, elem);
+ if (ns->prefix != NULL) {
+ VERROR(ctxt->userData,
+ "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
+ ns->prefix, elem->name, attrDecl->defaultValue);
+ } else {
+ VERROR(ctxt->userData,
+ "Value for attribute xmlns of %s is different from default \"%s\"\n",
+ elem->name, attrDecl->defaultValue);
+ }
+ ret = 0;
+ }
+ }
+
+ /* Validity Constraint: ID uniqueness */
+ if (attrDecl->atype == XML_ATTRIBUTE_ID) {
+ if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
+ ret = 0;
+ }
+
+ if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
+ (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
+ if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
+ ret = 0;
+ }
+
+ /* Validity Constraint: Notation Attributes */
+ if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
+ xmlEnumerationPtr tree = attrDecl->tree;
+ xmlNotationPtr nota;
+
+ /* First check that the given NOTATION was declared */
+ nota = xmlGetDtdNotationDesc(doc->intSubset, value);
+ if (nota == NULL)
+ nota = xmlGetDtdNotationDesc(doc->extSubset, value);
+
+ if (nota == NULL) {
+ VECTXT(ctxt, elem);
+ if (ns->prefix != NULL) {
+ VERROR(ctxt->userData,
+ "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
+ value, ns->prefix, elem->name);
+ } else {
+ VERROR(ctxt->userData,
+ "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
+ value, elem->name);
+ }
+ ret = 0;
+ }
+
+ /* Second, verify that it's among the list */
+ while (tree != NULL) {
+ if (xmlStrEqual(tree->name, value)) break;
+ tree = tree->next;
+ }
+ if (tree == NULL) {
+ VECTXT(ctxt, elem);
+ if (ns->prefix != NULL) {
+ VERROR(ctxt->userData,
+"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
+ value, ns->prefix, elem->name);
+ } else {
+ VERROR(ctxt->userData,
+"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
+ value, elem->name);
+ }
+ ret = 0;
+ }
+ }
+
+ /* Validity Constraint: Enumeration */
+ if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
+ xmlEnumerationPtr tree = attrDecl->tree;
+ while (tree != NULL) {
+ if (xmlStrEqual(tree->name, value)) break;
+ tree = tree->next;
+ }
+ if (tree == NULL) {
+ VECTXT(ctxt, elem);
+ if (ns->prefix != NULL) {
+ VERROR(ctxt->userData,
+"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
+ value, ns->prefix, elem->name);
+ } else {
+ VERROR(ctxt->userData,
+"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
+ value, elem->name);
+ }
+ ret = 0;
+ }
+ }
+
+ /* Fixed Attribute Default */
+ if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
+ (!xmlStrEqual(attrDecl->defaultValue, value))) {
+ VECTXT(ctxt, elem);
+ if (ns->prefix != NULL) {
+ VERROR(ctxt->userData,
+ "Value for attribute xmlns:%s of %s must be \"%s\"\n",
+ ns->prefix, elem->name, attrDecl->defaultValue);
+ } else {
+ VERROR(ctxt->userData,
+ "Value for attribute xmlns of %s must be \"%s\"\n",
+ elem->name, attrDecl->defaultValue);
+ }
+ ret = 0;
+ }
+
+ /* Extra check for the attribute value */
+ if (ns->prefix != NULL) {
+ ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
+ attrDecl->atype, value);
+ } else {
+ ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
+ attrDecl->atype, value);
+ }
+
+ return(ret);
+}
+
#ifndef LIBXML_REGEXP_ENABLED
/**
* xmlValidateSkipIgnorable: