- Large resync between W3C and Gnome tree
- configure.in: 2.1.0 prerelease
- example/Makefile.am example/gjobread.c tree.h: work on
libxml1 libxml2 convergence.
- nanoftp, nanohttp.c: fixed stalled connections probs
- HTMLtree.c SAX.c : support for attribute without values in
HTML for andersca
- valid.c: Fixed most validation + namespace problems
- HTMLparser.c: start document callback for andersca
- debugXML.c xpath.c: lots of XPath fixups from Picdar Technology
- parser.h, SAX.c: serious speed improvement for large
CDATA blocks
- encoding.[ch] xmlIO.[ch]: Improved seriously saving to
different encoding
- config.h.in parser.c xmllint.c: added xmlCheckVersion()
and the LIBXML_TEST_VERSION macro
Daniel
diff --git a/valid.c b/valid.c
index bc66ac5..5dc37ed 100644
--- a/valid.c
+++ b/valid.c
@@ -154,6 +154,61 @@
xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
+/************************************************************************
+ * *
+ * QName handling helper *
+ * *
+ ************************************************************************/
+
+/**
+ * xmlSplitQName2:
+ * @name: an XML parser context
+ * @prefix: a xmlChar **
+ *
+ * parse an XML qualified name string
+ *
+ * [NS 5] QName ::= (Prefix ':')? LocalPart
+ *
+ * [NS 6] Prefix ::= NCName
+ *
+ * [NS 7] LocalPart ::= NCName
+ *
+ * Returns NULL if not a QName, otherwise the local part, and prefix
+ * is updated to get the Prefix if any.
+ */
+
+xmlChar *
+xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
+ int len = 0;
+ xmlChar *ret = NULL;
+
+ *prefix = NULL;
+
+ /* xml: prefix is not really a namespace */
+ if ((name[0] == 'x') && (name[1] == 'm') &&
+ (name[2] == 'l') && (name[3] == ':'))
+ return(NULL);
+
+ /* nasty but valid */
+ if (name[0] == ':')
+ return(NULL);
+
+ /*
+ * we are not trying to validate but just to cut, and yes it will
+ * work even if this is as set of UTF-8 encoded chars
+ */
+ while ((name[len] != 0) && (name[len] != ':'))
+ len++;
+
+ if (name[len] == 0)
+ return(NULL);
+
+ *prefix = xmlStrndup(name, len);
+ ret = xmlStrdup(&name[len + 1]);
+
+ return(ret);
+}
+
/****************************************************************
* *
* Util functions for data allocation/deallocation *
@@ -428,6 +483,7 @@
xmlElementContentPtr content) {
xmlElementPtr ret, cur;
xmlElementTablePtr table;
+ xmlChar *ns, *uqname;
int i;
if (dtd == NULL) {
@@ -473,6 +529,13 @@
}
/*
+ * check if name is a QName
+ */
+ uqname = xmlSplitQName2(name, &ns);
+ if (uqname != NULL)
+ name = uqname;
+
+ /*
* Create the Element table if needed.
*/
table = dtd->elements;
@@ -489,7 +552,10 @@
*/
for (i = 0;i < table->nb_elements;i++) {
cur = table->table[i];
- if (!xmlStrcmp(cur->name, name)) {
+ if ((ns != NULL) && (cur->prefix == NULL)) continue;
+ if ((ns == NULL) && (cur->prefix != NULL)) continue;
+ if ((!xmlStrcmp(cur->name, name)) &&
+ ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
/*
* The element is already defined in this Dtd.
*/
@@ -527,6 +593,7 @@
*/
ret->etype = type;
ret->name = xmlStrdup(name);
+ ret->prefix = ns;
ret->content = xmlCopyElementContent(content);
ret->attributes = xmlScanAttributeDecl(dtd, name);
table->nb_elements++;
@@ -543,6 +610,8 @@
ret->prev = dtd->last;
dtd->last = (xmlNodePtr) ret;
}
+ if (uqname != NULL)
+ xmlFree(uqname);
return(ret);
}
@@ -559,6 +628,8 @@
xmlFreeElementContent(elem->content);
if (elem->name != NULL)
xmlFree((xmlChar *) elem->name);
+ if (elem->prefix != NULL)
+ xmlFree((xmlChar *) elem->prefix);
memset(elem, -1, sizeof(xmlElement));
xmlFree(elem);
}
@@ -896,7 +967,7 @@
*
* Register a new attribute declaration
*
- * Returns NULL if not, othervise the entity
+ * Returns NULL if not new, othervise the attribute decl
*/
xmlAttributePtr
xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
@@ -981,6 +1052,7 @@
*/
VWARNING(ctxt->userData, "Attribute %s on %s: already defined\n",
elem, name);
+ return(NULL);
}
}
@@ -1157,6 +1229,10 @@
xmlBufferWriteChar(buf, "<!ATTLIST ");
xmlBufferWriteCHAR(buf, attr->elem);
xmlBufferWriteChar(buf, " ");
+ if (attr->prefix != NULL) {
+ xmlBufferWriteCHAR(buf, attr->prefix);
+ xmlBufferWriteChar(buf, ":");
+ }
xmlBufferWriteCHAR(buf, attr->name);
switch (attr->atype) {
case XML_ATTRIBUTE_CDATA:
@@ -2066,6 +2142,7 @@
xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
xmlElementTablePtr table;
xmlElementPtr cur;
+ xmlChar *uqname = NULL, *prefix = NULL;
int i;
if (dtd == NULL) return(NULL);
@@ -2077,6 +2154,59 @@
if (!xmlStrcmp(cur->name, name))
return(cur);
}
+
+ /*
+ * Specific case if name is a QName.
+ */
+ uqname = xmlSplitQName2(name, &prefix);
+ if (uqname == NULL) return(NULL);
+
+ for (i = 0;i < table->nb_elements;i++) {
+ cur = table->table[i];
+ if ((!xmlStrcmp(cur->name, uqname)) &&
+ ((prefix == cur->prefix) ||
+ ((prefix != NULL) && (cur->prefix != NULL) &&
+ (!xmlStrcmp(cur->prefix, prefix))))) {
+ if (prefix != NULL) xmlFree(prefix);
+ if (uqname != NULL) xmlFree(uqname);
+ return(cur);
+ }
+ }
+ if (prefix != NULL) xmlFree(prefix);
+ if (uqname != NULL) xmlFree(uqname);
+ return(NULL);
+}
+
+/**
+ * xmlGetDtdQElementDesc:
+ * @dtd: a pointer to the DtD to search
+ * @name: the element name
+ * @prefix: the element namespace prefix
+ *
+ * Search the Dtd for the description of this element
+ *
+ * returns the xmlElementPtr if found or NULL
+ */
+
+xmlElementPtr
+xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
+ const xmlChar *prefix) {
+ xmlElementTablePtr table;
+ xmlElementPtr cur;
+ int i;
+
+ if (dtd == NULL) return(NULL);
+ if (dtd->elements == NULL) return(NULL);
+ table = dtd->elements;
+
+ for (i = 0;i < table->nb_elements;i++) {
+ cur = table->table[i];
+ if (!xmlStrcmp(cur->name, name) &&
+ ((prefix == cur->prefix) ||
+ ((prefix != NULL) && (cur->prefix != NULL) &&
+ (!xmlStrcmp(cur->prefix, prefix)))))
+ return(cur);
+ }
return(NULL);
}
@@ -2096,6 +2226,7 @@
xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
xmlAttributeTablePtr table;
xmlAttributePtr cur;
+ xmlChar *uqname = NULL, *prefix = NULL;
int i;
if (dtd == NULL) return(NULL);
@@ -2108,6 +2239,63 @@
(!xmlStrcmp(cur->elem, elem)))
return(cur);
}
+
+ /*
+ * Specific case if name is a QName.
+ */
+ uqname = xmlSplitQName2(name, &prefix);
+ if (uqname == NULL) return(NULL);
+
+ for (i = 0;i < table->nb_attributes;i++) {
+ cur = table->table[i];
+ if ((!xmlStrcmp(cur->name, uqname)) &&
+ (!xmlStrcmp(cur->elem, elem)) &&
+ ((prefix == cur->prefix) ||
+ ((prefix != NULL) && (cur->prefix != NULL) &&
+ (!xmlStrcmp(cur->prefix, prefix))))) {
+ if (prefix != NULL) xmlFree(prefix);
+ if (uqname != NULL) xmlFree(uqname);
+ return(cur);
+ }
+ }
+ if (prefix != NULL) xmlFree(prefix);
+ if (uqname != NULL) xmlFree(uqname);
+ return(NULL);
+}
+
+/**
+ * xmlGetDtdQAttrDesc:
+ * @dtd: a pointer to the DtD to search
+ * @elem: the element name
+ * @name: the attribute name
+ * @prefix: the attribute namespace prefix
+ *
+ * Search the Dtd for the description of this qualified attribute on
+ * this element.
+ *
+ * returns the xmlAttributePtr if found or NULL
+ */
+
+xmlAttributePtr
+xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
+ const xmlChar *prefix) {
+ xmlAttributeTablePtr table;
+ xmlAttributePtr cur;
+ int i;
+
+ if (dtd == NULL) return(NULL);
+ if (dtd->attributes == NULL) return(NULL);
+ table = dtd->attributes;
+
+ for (i = 0;i < table->nb_attributes;i++) {
+ cur = table->table[i];
+ if ((!xmlStrcmp(cur->name, name)) &&
+ (!xmlStrcmp(cur->elem, elem)) &&
+ ((prefix == cur->prefix) ||
+ ((prefix != NULL) && (cur->prefix != NULL) &&
+ (!xmlStrcmp(cur->prefix, prefix)))))
+ return(cur);
+ }
return(NULL);
}
@@ -2586,13 +2774,25 @@
const xmlChar *name, const xmlChar *value) {
xmlChar *ret, *dst;
const xmlChar *src;
- xmlAttributePtr attrDecl;
+ xmlAttributePtr attrDecl = NULL;
if (doc == NULL) return(NULL);
if (elem == NULL) return(NULL);
if (name == NULL) return(NULL);
if (value == NULL) return(NULL);
+ if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
+ xmlChar qname[500];
+#ifdef HAVE_SNPRINTF
+ snprintf((char *) qname, sizeof(qname), "%s:%s",
+ elem->ns->prefix, elem->name);
+#else
+ sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
+#endif
+ attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))
+ attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
+ }
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
if ((attrDecl == NULL) && (doc->extSubset != NULL))
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
@@ -2850,7 +3050,7 @@
xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
/* xmlElementPtr elemDecl; */
- xmlAttributePtr attrDecl;
+ xmlAttributePtr attrDecl = NULL;
int val;
int ret = 1;
@@ -2858,9 +3058,42 @@
if ((elem == NULL) || (elem->name == NULL)) return(0);
if ((attr == NULL) || (attr->name == NULL)) return(0);
- attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
- if ((attrDecl == NULL) && (doc->extSubset != NULL))
- attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
+ if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
+ xmlChar qname[500];
+#ifdef HAVE_SNPRINTF
+ snprintf((char *) qname, sizeof(qname), "%s:%s",
+ elem->ns->prefix, elem->name);
+#else
+ sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
+#endif
+ if (attr->ns != NULL) {
+ attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
+ attr->name, attr->ns->prefix);
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))
+ attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
+ attr->name, attr->ns->prefix);
+ } else {
+ attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))
+ attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
+ qname, attr->name);
+ }
+ }
+ if (attrDecl == NULL) {
+ if (attr->ns != NULL) {
+ attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
+ attr->name, attr->ns->prefix);
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))
+ attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
+ attr->name, attr->ns->prefix);
+ } else {
+ attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
+ elem->name, attr->name);
+ if ((attrDecl == NULL) && (doc->extSubset != NULL))
+ attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
+ elem->name, attr->name);
+ }
+ }
/* Validity Constraint: Attribute Value Type */
@@ -3274,7 +3507,7 @@
int
xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
xmlNodePtr elem) {
- xmlElementPtr elemDecl;
+ xmlElementPtr elemDecl = NULL;
xmlElementContentPtr cont;
xmlAttributePtr attr;
xmlNodePtr child;
@@ -3347,9 +3580,25 @@
}
if (elem->name == NULL) return(0);
- elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
- if ((elemDecl == NULL) && (doc->extSubset != NULL))
- elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
+ /*
+ * Fetch the declaration for the qualified name
+ */
+ if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
+ elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
+ elem->name, elem->ns->prefix);
+ if ((elemDecl == NULL) && (doc->extSubset != NULL))
+ elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
+ elem->name, elem->ns->prefix);
+ }
+
+ /*
+ * Fetch the declaration for the non qualified name
+ */
+ if (elemDecl == NULL) {
+ elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
+ if ((elemDecl == NULL) && (doc->extSubset != NULL))
+ elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
+ }
if (elemDecl == NULL) {
VERROR(ctxt->userData, "No declaration for element %s\n",
elem->name);
@@ -3375,6 +3624,34 @@
while (child != NULL) {
if (child->type == XML_ELEMENT_NODE) {
name = child->name;
+ if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
+ xmlChar qname[500];
+#ifdef HAVE_SNPRINTF
+ snprintf((char *) qname, sizeof(qname), "%s:%s",
+ child->ns->prefix, child->name);
+#else
+ sprintf(qname, "%s:%s", child->name, child->ns->prefix);
+#endif
+ cont = elemDecl->content;
+ while (cont != NULL) {
+ if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
+ if (!xmlStrcmp(cont->name, qname)) break;
+ } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
+ (cont->c1 != NULL) &&
+ (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
+ if (!xmlStrcmp(cont->c1->name, qname)) break;
+ } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
+ (cont->c1 == NULL) ||
+ (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
+ /* Internal error !!! */
+ fprintf(stderr, "Internal: MIXED struct bad\n");
+ break;
+ }
+ cont = cont->c2;
+ }
+ if (cont != NULL)
+ goto child_ok;
+ }
cont = elemDecl->content;
while (cont != NULL) {
if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
@@ -3399,6 +3676,7 @@
ret = 0;
}
}
+child_ok:
child = child->next;
}
break;
@@ -3518,15 +3796,32 @@
VERROR(ctxt->userData, "Not valid: no root element\n");
return(0);
}
+
+ /*
+ * Check first the document root against the NQName
+ */
if (xmlStrcmp(doc->intSubset->name, root->name)) {
- if ((xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) ||
- (xmlStrcmp(root->name, BAD_CAST "html"))) {
- VERROR(ctxt->userData,
- "Not valid: root and DtD name do not match '%s' and '%s'\n",
- root->name, doc->intSubset->name);
- return(0);
- }
+ if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
+ xmlChar qname[500];
+#ifdef HAVE_SNPRINTF
+ snprintf((char *) qname, sizeof(qname), "%s:%s",
+ root->ns->prefix, root->name);
+#else
+ sprintf(qname, "%s:%s", root->name, root->ns->prefix);
+#endif
+ if (!xmlStrcmp(doc->intSubset->name, qname))
+ goto name_ok;
+ }
+ if ((!xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) &&
+ (!xmlStrcmp(root->name, BAD_CAST "html")))
+ goto name_ok;
+ VERROR(ctxt->userData,
+ "Not valid: root and DtD name do not match '%s' and '%s'\n",
+ root->name, doc->intSubset->name);
+ return(0);
+
}
+name_ok:
return(1);
}