This is the 2.0.0-beta, lots and lots and lots of changes
Have a look at http://xmlsoft.org/upgrade.html
Daniel
diff --git a/SAX.c b/SAX.c
index 35d8013..10c6a83 100644
--- a/SAX.c
+++ b/SAX.c
@@ -158,66 +158,112 @@
name, ExternalID, SystemID);
#endif
xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
+}
+
+/**
+ * externalSubset:
+ * @ctx: the user data (XML parser context)
+ *
+ * Callback on external subset declaration.
+ */
+void
+externalSubset(void *ctx, const xmlChar *name,
+ const xmlChar *ExternalID, const xmlChar *SystemID)
+{
+ xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.externalSubset(%s, %s, %s)\n",
+ name, ExternalID, SystemID);
+#endif
if (((ExternalID != NULL) || (SystemID != NULL)) &&
(ctxt->validate && ctxt->wellFormed && ctxt->myDoc)) {
/*
* Try to fetch and parse the external subset.
*/
- xmlDtdPtr ret = NULL;
- xmlParserCtxtPtr dtdCtxt;
+ xmlParserInputPtr oldinput;
+ int oldinputNr;
+ int oldinputMax;
+ xmlParserInputPtr *oldinputTab;
+ int oldwellFormed;
xmlParserInputPtr input = NULL;
xmlCharEncoding enc;
- dtdCtxt = xmlNewParserCtxt();
- if (dtdCtxt == NULL) return;
-
/*
* Ask the Entity resolver to load the damn thing
*/
- if ((ctxt->directory != NULL) && (dtdCtxt->directory == NULL))
- dtdCtxt->directory = (char *) xmlStrdup(BAD_CAST ctxt->directory);
-
- if ((dtdCtxt->sax != NULL) && (dtdCtxt->sax->resolveEntity != NULL))
- input = dtdCtxt->sax->resolveEntity(dtdCtxt->userData, ExternalID,
+ if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
+ input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID,
SystemID);
if (input == NULL) {
- xmlFreeParserCtxt(dtdCtxt);
return;
}
+ xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID);
+
/*
- * plug some encoding conversion routines here. !!!
+ * make sure we won't destroy the main document context
*/
- xmlPushInput(dtdCtxt, input);
- enc = xmlDetectCharEncoding(dtdCtxt->input->cur);
- xmlSwitchEncoding(dtdCtxt, enc);
+ oldinput = ctxt->input;
+ oldinputNr = ctxt->inputNr;
+ oldinputMax = ctxt->inputMax;
+ oldinputTab = ctxt->inputTab;
+ oldwellFormed = ctxt->wellFormed;
+
+ ctxt->inputTab = (xmlParserInputPtr *)
+ xmlMalloc(5 * sizeof(xmlParserInputPtr));
+ if (ctxt->inputTab == NULL) {
+ ctxt->errNo = XML_ERR_NO_MEMORY;
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt->userData,
+ "externalSubset: out of memory\n");
+ ctxt->errNo = XML_ERR_NO_MEMORY;
+ ctxt->input = oldinput;
+ ctxt->inputNr = oldinputNr;
+ ctxt->inputMax = oldinputMax;
+ ctxt->inputTab = oldinputTab;
+ return;
+ }
+ ctxt->inputNr = 0;
+ ctxt->inputMax = 5;
+ ctxt->input = NULL;
+ xmlPushInput(ctxt, input);
+
+ /*
+ * On the fly encoding conversion if needed
+ */
+ enc = xmlDetectCharEncoding(ctxt->input->cur, 4);
+ xmlSwitchEncoding(ctxt, enc);
if (input->filename == NULL)
input->filename = (char *) xmlStrdup(SystemID);
input->line = 1;
input->col = 1;
- input->base = dtdCtxt->input->cur;
- input->cur = dtdCtxt->input->cur;
+ input->base = ctxt->input->cur;
+ input->cur = ctxt->input->cur;
input->free = NULL;
/*
* let's parse that entity knowing it's an external subset.
*/
- xmlParseExternalSubset(dtdCtxt, ExternalID, SystemID);
+ xmlParseExternalSubset(ctxt, ExternalID, SystemID);
- if (dtdCtxt->myDoc != NULL) {
- if (dtdCtxt->wellFormed) {
- ret = dtdCtxt->myDoc->intSubset;
- dtdCtxt->myDoc->intSubset = NULL;
- } else {
- ret = NULL;
- }
- xmlFreeDoc(dtdCtxt->myDoc);
- dtdCtxt->myDoc = NULL;
- }
- xmlFreeParserCtxt(dtdCtxt);
-
- ctxt->myDoc->extSubset = ret;
+ /*
+ * Free up the external entities
+ */
+
+ while (ctxt->inputNr > 1)
+ xmlPopInput(ctxt);
+ xmlFreeInputStream(ctxt->input);
+ xmlFree(ctxt->inputTab);
+
+ /*
+ * Restore the parsing context of the main entity
+ */
+ ctxt->input = oldinput;
+ ctxt->inputNr = oldinputNr;
+ ctxt->inputMax = oldinputMax;
+ ctxt->inputTab = oldinputTab;
+ /* ctxt->wellFormed = oldwellFormed; */
}
}
@@ -316,13 +362,23 @@
fprintf(stderr, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
name, type, publicId, systemId, content);
#endif
- xmlAddDocEntity(ctxt->myDoc, name, type, publicId, systemId, content);
+ if (ctxt->inSubset == 1)
+ xmlAddDocEntity(ctxt->myDoc, name, type, publicId,
+ systemId, content);
+ else if (ctxt->inSubset == 2)
+ xmlAddDtdEntity(ctxt->myDoc, name, type, publicId,
+ systemId, content);
+ else {
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt,
+ "SAX.entityDecl(%s) called while not in subset\n", name);
+ }
}
/**
* attributeDecl:
* @ctx: the user data (XML parser context)
- * @name: the attribute name
+ * @fullname: the attribute name
* @type: the attribute type
* @publicId: The public ID of the attribute
* @systemId: The system ID of the attribute
@@ -331,24 +387,40 @@
* An attribute definition has been parsed
*/
void
-attributeDecl(void *ctx, const xmlChar *elem, const xmlChar *name,
+attributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname,
int type, int def, const xmlChar *defaultValue,
xmlEnumerationPtr tree)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlAttributePtr attr;
+ xmlChar *name = NULL, *prefix = NULL;
#ifdef DEBUG_SAX
fprintf(stderr, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
- elem, name, type, def, defaultValue);
+ elem, fullname, type, def, defaultValue);
#endif
- attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
- name, type, def, defaultValue, tree);
+ name = xmlSplitQName(ctxt, fullname, &prefix);
+ if (ctxt->inSubset == 1)
+ attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
+ name, prefix, type, def, defaultValue, tree);
+ else if (ctxt->inSubset == 2)
+ attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, elem,
+ name, prefix, type, def, defaultValue, tree);
+ else {
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt,
+ "SAX.attributeDecl(%s) called while not in subset\n", name);
+ return;
+ }
if (attr == 0) ctxt->valid = 0;
if (ctxt->validate && ctxt->wellFormed &&
ctxt->myDoc && ctxt->myDoc->intSubset)
ctxt->valid &= xmlValidateAttributeDecl(&ctxt->vctxt, ctxt->myDoc,
attr);
+ if (prefix != NULL)
+ xmlFree(prefix);
+ if (name != NULL)
+ xmlFree(name);
}
/**
@@ -367,16 +439,26 @@
xmlElementContentPtr content)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
- xmlElementPtr elem;
+ xmlElementPtr elem = NULL;
#ifdef DEBUG_SAX
fprintf(stderr, "SAX.elementDecl(%s, %d, ...)\n",
- name, type);
+ fullname, type);
#endif
- elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset,
+ if (ctxt->inSubset == 1)
+ elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset,
name, type, content);
- if (elem == 0) ctxt->valid = 0;
+ else if (ctxt->inSubset == 2)
+ elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->extSubset,
+ name, type, content);
+ else {
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt,
+ "SAX.elementDecl(%s) called while not in subset\n", name);
+ return;
+ }
+ if (elem == NULL) ctxt->valid = 0;
if (ctxt->validate && ctxt->wellFormed &&
ctxt->myDoc && ctxt->myDoc->intSubset)
ctxt->valid &= xmlValidateElementDecl(&ctxt->vctxt, ctxt->myDoc, elem);
@@ -396,15 +478,25 @@
const xmlChar *publicId, const xmlChar *systemId)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
- xmlNotationPtr nota;
+ xmlNotationPtr nota = NULL;
#ifdef DEBUG_SAX
fprintf(stderr, "SAX.notationDecl(%s, %s, %s)\n", name, publicId, systemId);
#endif
- nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
+ if (ctxt->inSubset == 1)
+ nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
publicId, systemId);
- if (nota == 0) ctxt->valid = 0;
+ else if (ctxt->inSubset == 2)
+ nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
+ publicId, systemId);
+ else {
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt,
+ "SAX.notationDecl(%s) called while not in subset\n", name);
+ return;
+ }
+ if (nota == NULL) ctxt->valid = 0;
if (ctxt->validate && ctxt->wellFormed &&
ctxt->myDoc && ctxt->myDoc->intSubset)
ctxt->valid &= xmlValidateNotationDecl(&ctxt->vctxt, ctxt->myDoc,
@@ -518,6 +610,7 @@
xmlAttrPtr ret;
xmlChar *name;
xmlChar *ns;
+ xmlChar *nval;
xmlNsPtr namespace;
/****************
@@ -528,7 +621,15 @@
/*
* Split the full name into a namespace prefix and the tag name
*/
- name = xmlSplitQName(fullname, &ns);
+ name = xmlSplitQName(ctxt, fullname, &ns);
+
+ /*
+ * Do the last stave of the attribute normalization
+ */
+ nval = xmlValidNormalizeAttributeValue(ctxt->myDoc,
+ ctxt->node, fullname, value);
+ if (nval != NULL)
+ value = nval;
/*
* Check whether it's a namespace definition
@@ -540,15 +641,28 @@
xmlNewNs(ctxt->node, value, NULL);
if (name != NULL)
xmlFree(name);
+ if (nval != NULL)
+ xmlFree(nval);
return;
}
if ((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);
+ */
/* a standard namespace definition */
xmlNewNs(ctxt->node, value, name);
xmlFree(ns);
if (name != NULL)
xmlFree(name);
+ if (nval != NULL)
+ xmlFree(nval);
return;
}
@@ -562,17 +676,52 @@
ret = xmlNewNsProp(ctxt->node, namespace, name, NULL);
if (ret != NULL) {
- if ((ctxt->replaceEntities == 0) && (!ctxt->html))
- ret->val = xmlStringGetNodeList(ctxt->myDoc, value);
- else
- ret->val = xmlNewDocText(ctxt->myDoc, value);
+ if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
+ xmlNodePtr tmp;
+
+ ret->children = xmlStringGetNodeList(ctxt->myDoc, value);
+ tmp = ret->children;
+ while (tmp != NULL) {
+ tmp->parent = (xmlNodePtr) ret;
+ if (tmp->next == NULL)
+ ret->last = tmp;
+ tmp = tmp->next;
+ }
+ } else {
+ ret->children = xmlNewDocText(ctxt->myDoc, value);
+ ret->last = ret->children;
+ if (ret->children != NULL)
+ ret->children->parent = (xmlNodePtr) ret;
+ }
}
if (ctxt->validate && ctxt->wellFormed &&
- ctxt->myDoc && ctxt->myDoc->intSubset)
- ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
+ ctxt->myDoc && ctxt->myDoc->intSubset) {
+
+ /*
+ * If we don't substitute entities, the validation should be
+ * done on a value with replaced entities anyway.
+ */
+ if (!ctxt->replaceEntities) {
+ xmlChar *val;
+
+ ctxt->depth++;
+ val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
+ 0,0,0);
+ ctxt->depth--;
+ if (val == NULL)
+ ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
+ ctxt->myDoc, ctxt->node, ret, value);
+ else {
+ ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
+ ctxt->myDoc, ctxt->node, ret, val);
+ xmlFree(val);
+ }
+ } else {
+ ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
ctxt->node, ret, value);
- else {
+ }
+ } else {
/*
* when validating, the ID registration is done at the attribute
* validation level. Otherwise we have to do specific handling here.
@@ -583,6 +732,8 @@
xmlAddRef(&ctxt->vctxt, ctxt->myDoc, value, ret);
}
+ if (nval != NULL)
+ xmlFree(nval);
if (name != NULL)
xmlFree(name);
if (ns != NULL)
@@ -634,7 +785,7 @@
/*
* Split the full name into a namespace prefix and the tag name
*/
- name = xmlSplitQName(fullname, &prefix);
+ name = xmlSplitQName(ctxt, fullname, &prefix);
/*
@@ -644,13 +795,13 @@
*/
ret = xmlNewDocNode(ctxt->myDoc, NULL, name, NULL);
if (ret == NULL) return;
- if (ctxt->myDoc->root == NULL) {
+ if (ctxt->myDoc->children == NULL) {
#ifdef DEBUG_SAX_TREE
fprintf(stderr, "Setting %s as root\n", name);
#endif
- ctxt->myDoc->root = ret;
+ xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
} else if (parent == NULL) {
- parent = ctxt->myDoc->root;
+ parent = ctxt->myDoc->children;
}
/*
@@ -680,6 +831,15 @@
}
/*
+ * If it's the Document root, finish the Dtd validation and
+ * check the document root element for validity
+ */
+ if ((ctxt->validate) && (ctxt->vctxt.finishDtd == 0)) {
+ ctxt->valid &= xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc);
+ ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
+ ctxt->vctxt.finishDtd = 1;
+ }
+ /*
* process all the attributes whose name start with "xml"
*/
if (atts != NULL) {
@@ -790,7 +950,10 @@
#ifdef DEBUG_SAX
fprintf(stderr, "SAX.reference(%s)\n", name);
#endif
- ret = xmlNewReference(ctxt->myDoc, name);
+ if (name[0] == '#')
+ ret = xmlNewCharRef(ctxt->myDoc, name);
+ else
+ ret = xmlNewReference(ctxt->myDoc, name);
#ifdef DEBUG_SAX_TREE
fprintf(stderr, "add reference %s to %s \n", name, ctxt->node->name);
#endif
@@ -884,30 +1047,34 @@
ret = xmlNewPI(target, data);
if (ret == NULL) return;
- ret->doc = ctxt->myDoc;
- if (ctxt->myDoc->root == NULL) {
+ parent = ctxt->node;
+
+ if (ctxt->inSubset == 1) {
+ xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
+ return;
+ } else if (ctxt->inSubset == 2) {
+ xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
+ return;
+ }
+ if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
#ifdef DEBUG_SAX_TREE
fprintf(stderr, "Setting PI %s as root\n", target);
#endif
- ctxt->myDoc->root = ret;
- } else if (parent == NULL) {
- parent = ctxt->myDoc->root;
+ xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
+ return;
}
- if (parent != NULL) {
- if (parent->type == XML_ELEMENT_NODE) {
+ if (parent->type == XML_ELEMENT_NODE) {
#ifdef DEBUG_SAX_TREE
- fprintf(stderr, "adding PI child %s to %s\n", target, parent->name);
+ fprintf(stderr, "adding PI %s child to %s\n", target, parent->name);
#endif
- xmlAddChild(parent, ret);
- } else {
+ xmlAddChild(parent, ret);
+ } else {
#ifdef DEBUG_SAX_TREE
- fprintf(stderr, "adding PI sibling %s to ", target);
- xmlDebugDumpOneNode(stderr, parent, 0);
+ fprintf(stderr, "adding PI %s sibling to ", target);
+ xmlDebugDumpOneNode(stderr, parent, 0);
#endif
- xmlAddSibling(parent, ret);
- }
+ xmlAddSibling(parent, ret);
}
-
}
/**
@@ -1064,27 +1231,31 @@
ret = xmlNewDocComment(ctxt->myDoc, value);
if (ret == NULL) return;
- if (ctxt->myDoc->root == NULL) {
+ if (ctxt->inSubset == 1) {
+ xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
+ return;
+ } else if (ctxt->inSubset == 2) {
+ xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
+ return;
+ }
+ if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
#ifdef DEBUG_SAX_TREE
fprintf(stderr, "Setting comment as root\n");
#endif
- ctxt->myDoc->root = ret;
- } else if (parent == NULL) {
- parent = ctxt->myDoc->root;
+ xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
+ return;
}
- if (parent != NULL) {
- if (parent->type == XML_ELEMENT_NODE) {
+ if (parent->type == XML_ELEMENT_NODE) {
#ifdef DEBUG_SAX_TREE
- fprintf(stderr, "adding comment child to %s\n", parent->name);
+ fprintf(stderr, "adding comment child to %s\n", parent->name);
#endif
- xmlAddChild(parent, ret);
- } else {
+ xmlAddChild(parent, ret);
+ } else {
#ifdef DEBUG_SAX_TREE
- fprintf(stderr, "adding comment sibling to ");
- xmlDebugDumpOneNode(stderr, parent, 0);
+ fprintf(stderr, "adding comment sibling to ");
+ xmlDebugDumpOneNode(stderr, parent, 0);
#endif
- xmlAddSibling(parent, ret);
- }
+ xmlAddSibling(parent, ret);
}
}
@@ -1148,6 +1319,7 @@
xmlParserError,
getParameterEntity,
cdataBlock,
+ externalSubset,
};
/**
@@ -1159,6 +1331,7 @@
xmlDefaultSAXHandlerInit(void)
{
xmlDefaultSAXHandler.internalSubset = internalSubset;
+ xmlDefaultSAXHandler.externalSubset = externalSubset;
xmlDefaultSAXHandler.isStandalone = isStandalone;
xmlDefaultSAXHandler.hasInternalSubset = hasInternalSubset;
xmlDefaultSAXHandler.hasExternalSubset = hasExternalSubset;
@@ -1181,7 +1354,10 @@
xmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
xmlDefaultSAXHandler.processingInstruction = processingInstruction;
xmlDefaultSAXHandler.comment = comment;
- xmlDefaultSAXHandler.warning = xmlParserWarning;
+ if (xmlGetWarningsDefaultValue == 0)
+ xmlDefaultSAXHandler.warning = NULL;
+ else
+ xmlDefaultSAXHandler.warning = xmlParserWarning;
xmlDefaultSAXHandler.error = xmlParserError;
xmlDefaultSAXHandler.fatalError = xmlParserError;
}
@@ -1216,6 +1392,7 @@
xmlParserError,
getParameterEntity,
NULL,
+ NULL,
};
/**
@@ -1227,6 +1404,7 @@
htmlDefaultSAXHandlerInit(void)
{
htmlDefaultSAXHandler.internalSubset = NULL;
+ htmlDefaultSAXHandler.externalSubset = NULL;
htmlDefaultSAXHandler.isStandalone = NULL;
htmlDefaultSAXHandler.hasInternalSubset = NULL;
htmlDefaultSAXHandler.hasExternalSubset = NULL;