diff --git a/ChangeLog b/ChangeLog index 77e68ed9..441a0a17 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Thu Sep 26 17:33:46 CEST 2002 Daniel Veillard + + * 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 * HTMLtree.c: fixing bug #94241 on HTML boolean attributes diff --git a/SAX.c b/SAX.c index 9cf06a07..c8452ebf 100644 --- a/SAX.c +++ b/SAX.c @@ -795,18 +795,20 @@ endDocument(void *ctx) } /** - * 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 @@ attribute(void *ctx, const xmlChar *fullname, const xmlChar *value) 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 @@ attribute(void *ctx, const xmlChar *fullname, const xmlChar *value) } /* 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 @@ attribute(void *ctx, const xmlChar *fullname, const xmlChar *value) 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 @@ attribute(void *ctx, const xmlChar *fullname, const xmlChar *value) 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 @@ startElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) 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 5535dd9e..4cc5f978 100644 --- a/include/libxml/valid.h +++ b/include/libxml/valid.h @@ -264,6 +264,12 @@ int xmlValidateOneAttribute (xmlValidCtxtPtr ctxt, 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 3e8cb74a..4868dc58 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 12282be6..01e3253b 100644 --- a/result/valid/dia.xml +++ b/result/valid/dia.xml @@ -1,6 +1,7 @@ + diff --git a/test/valid/dia.xml b/test/valid/dia.xml index b6441abd..3ab3d068 100644 --- a/test/valid/dia.xml +++ b/test/valid/dia.xml @@ -1,6 +1,9 @@ + + diff --git a/valid.c b/valid.c index 9ebdbf5b..58ab756b 100644 --- a/valid.c +++ b/valid.c @@ -3817,6 +3817,232 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 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: