Completed/revamped the SAX support, removed old namespace suppport, Daniel
diff --git a/SAX.c b/SAX.c
index b4a6cb1..7f9ea18 100644
--- a/SAX.c
+++ b/SAX.c
@@ -10,6 +10,8 @@
#include <stdlib.h>
#include "tree.h"
#include "parser.h"
+#include "parserInternals.h"
+#include "valid.h"
#include "entities.h"
#include "xml-error.h"
@@ -81,6 +83,65 @@
};
/**
+ * isStandalone:
+ * @ctxt: An XML parser context
+ *
+ * Is this document tagged standalone ?
+ *
+ * Returns 1 if true
+ */
+int
+isStandalone(xmlParserCtxtPtr ctxt)
+{
+ return(ctxt->myDoc->standalone == 1);
+}
+
+/**
+ * hasInternalSubset:
+ * @ctxt: An XML parser context
+ *
+ * Does this document has an internal subset
+ *
+ * Returns 1 if true
+ */
+int
+hasInternalSubset(xmlParserCtxtPtr ctxt)
+{
+ return(ctxt->myDoc->intSubset != NULL);
+}
+
+/**
+ * hasExternalSubset:
+ * @ctxt: An XML parser context
+ *
+ * Does this document has an external subset
+ *
+ * Returns 1 if true
+ */
+int
+hasExternalSubset(xmlParserCtxtPtr ctxt)
+{
+ return(ctxt->myDoc->extSubset != NULL);
+}
+
+/**
+ * hasInternalSubset:
+ * @ctxt: An XML parser context
+ *
+ * Does this document has an internal subset
+ */
+void
+internalSubset(xmlParserCtxtPtr ctxt, const CHAR *name,
+ const CHAR *ExternalID, const CHAR *SystemID)
+{
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.internalSubset(%s, %s, %s)\n",
+ name, ExternalID, SystemID);
+#endif
+ xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
+}
+
+/**
* resolveEntity:
* @ctxt: An XML parser context
* @publicId: The public ID of the entity
@@ -102,10 +163,107 @@
fprintf(stderr, "SAX.resolveEntity(%s, %s)\n", publicId, systemId);
#endif
+ /*
+ * TODO : not 100% sure that the appropriate handling in that case.
+ */
return(NULL);
}
/**
+ * getEntity:
+ * @ctxt: An XML parser context
+ * @name: The entity name
+ *
+ * Get an entity by name
+ *
+ * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
+ */
+xmlEntityPtr
+getEntity(xmlParserCtxtPtr ctxt, const CHAR *name)
+{
+ xmlEntityPtr ret;
+
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.getEntity(%s)\n", name);
+#endif
+
+ ret = xmlGetDocEntity(ctxt->myDoc, name);
+ return(ret);
+}
+
+
+/**
+ * entityDecl:
+ * @ctxt: An XML parser context
+ * @name: the entity name
+ * @type: the entity type
+ * @publicId: The public ID of the entity
+ * @systemId: The system ID of the entity
+ * @content: the entity value (without processing).
+ *
+ * An entity definition has been parsed
+ */
+void
+entityDecl(xmlParserCtxtPtr ctxt, const CHAR *name, int type,
+ const CHAR *publicId, const CHAR *systemId, CHAR *content)
+{
+
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
+ name, type, publicId, systemId, content);
+#endif
+ xmlAddDocEntity(ctxt->myDoc, name, type, publicId, systemId, content);
+}
+
+/**
+ * attributeDecl:
+ * @ctxt: An XML parser context
+ * @name: the attribute name
+ * @type: the attribute type
+ * @publicId: The public ID of the attribute
+ * @systemId: The system ID of the attribute
+ * @content: the attribute value (without processing).
+ *
+ * An attribute definition has been parsed
+ */
+void
+attributeDecl(xmlParserCtxtPtr ctxt, const CHAR *elem, const CHAR *name,
+ int type, int def, const CHAR *defaultValue,
+ xmlEnumerationPtr tree)
+{
+
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
+ elem, name, type, def, defaultValue);
+#endif
+ xmlAddAttributeDecl(ctxt->myDoc->intSubset, elem, name, type, def,
+ defaultValue, tree);
+}
+
+/**
+ * elementDecl:
+ * @ctxt: An XML parser context
+ * @name: the element name
+ * @type: the element type
+ * @publicId: The public ID of the element
+ * @systemId: The system ID of the element
+ * @content: the element value (without processing).
+ *
+ * An element definition has been parsed
+ */
+void
+elementDecl(xmlParserCtxtPtr ctxt, const CHAR *name, int type,
+ xmlElementContentPtr content)
+{
+
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.elementDecl(%s, %d, ...)\n",
+ name, type);
+#endif
+ xmlAddElementDecl(ctxt->myDoc->intSubset, name, type, content);
+}
+
+/**
* notationDecl:
* @ctxt: An XML parser context
* @name: The name of the notation
@@ -122,6 +280,7 @@
#ifdef DEBUG_SAX
fprintf(stderr, "SAX.notationDecl(%s, %s, %s)\n", name, publicId, systemId);
#endif
+ xmlAddNotationDecl(ctxt->myDoc->intSubset, name, publicId, systemId);
}
/**
@@ -171,9 +330,19 @@
void
startDocument(xmlParserCtxtPtr ctxt)
{
+ xmlDocPtr doc;
+
#ifdef DEBUG_SAX
fprintf(stderr, "SAX.startDocument()\n");
#endif
+ doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
+ if (doc != NULL) {
+ if (ctxt->encoding != NULL)
+ doc->encoding = xmlStrdup(ctxt->encoding);
+ else
+ doc->encoding = NULL;
+ doc->standalone = ctxt->standalone;
+ }
}
/**
@@ -191,19 +360,151 @@
}
/**
+ * attribute:
+ * @ctxt: An XML parser context
+ * @name: The attribute name
+ * @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(xmlParserCtxtPtr ctxt, const CHAR *fullname, const CHAR *value)
+{
+ xmlAttrPtr ret;
+ CHAR *name;
+ CHAR *ns;
+
+/****************
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.attribute(%s, %s)\n", fullname, value);
+#endif
+ ****************/
+ /*
+ * Split the full name into a namespace prefix and the tag name
+ */
+ name = xmlSplitQName(fullname, &ns);
+
+ /*
+ * Check whether it's a namespace definition
+ */
+ if ((ns == NULL) &&
+ (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
+ (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
+ /* a default namespace definition */
+ xmlNewNs(ctxt->node, value, NULL);
+ if (name != NULL)
+ free(name);
+ return;
+ }
+ if ((ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
+ (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
+ /* a standard namespace definition */
+ xmlNewNs(ctxt->node, value, name);
+ free(ns);
+ if (name != NULL)
+ free(name);
+ return;
+ }
+
+ ret = xmlNewProp(ctxt->node, name, NULL);
+ if (ret != NULL)
+ ret->val = xmlStringGetNodeList(ctxt->myDoc, value);
+ if (name != NULL)
+ free(name);
+ if (ns != NULL)
+ free(ns);
+}
+
+/**
* startElement:
* @ctxt: An XML parser context
* @name: The element name
+ * @atts: An array of name/value attributes pairs, NULL terminated
*
* called when an opening tag has been processed.
* TODO We currently have a small pblm with the arguments ...
*/
void
-startElement(xmlParserCtxtPtr ctxt, const CHAR *name)
+startElement(xmlParserCtxtPtr ctxt, const CHAR *fullname, const CHAR **atts)
{
+ xmlNodePtr ret;
+ xmlNodePtr parent = ctxt->node;
+ xmlNsPtr ns;
+ CHAR *name;
+ CHAR *prefix;
+ const CHAR *att;
+ const CHAR *value;
+
+ int i;
+
#ifdef DEBUG_SAX
- fprintf(stderr, "SAX.startElement(%s)\n", name);
+ fprintf(stderr, "SAX.startElement(%s)\n", fullname);
#endif
+ /*
+ * Split the full name into a namespace prefix and the tag name
+ */
+ name = xmlSplitQName(fullname, &prefix);
+
+
+ /*
+ * Note : the namespace resolution is deferred until the end of the
+ * attributes parsing, since local namespace can be defined as
+ * an attribute at this level.
+ */
+ ret = xmlNewDocNode(ctxt->myDoc, NULL, name, NULL);
+ if (ret == NULL) return;
+ if (ctxt->myDoc->root == NULL)
+ ctxt->myDoc->root = ret;
+
+ /*
+ * We are parsing a new node.
+ */
+ nodePush(ctxt, ret);
+
+ /*
+ * Link the child element
+ */
+ if (parent != NULL)
+ xmlAddChild(parent, ctxt->node);
+
+ /*
+ * process all the attributes.
+ */
+ if (atts != NULL) {
+ i = 0;
+ att = atts[i++];
+ value = atts[i++];
+ while ((att != NULL) && (value != NULL)) {
+ /*
+ * Handle one pair of attribute/value
+ */
+ attribute(ctxt, att, value);
+
+ /*
+ * Next ones
+ */
+ att = atts[i++];
+ value = atts[i++];
+ }
+ }
+
+ /*
+ * Search the namespace, note that since the attributes have been
+ * processed, the local namespaces are available.
+ */
+ ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
+ if ((ns == NULL) && (parent != NULL))
+ ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
+ xmlSetNs(ret, ns);
+
+ if (prefix != NULL)
+ free(prefix);
+ if (name != NULL)
+ free(name);
+
}
/**
@@ -216,47 +517,65 @@
void
endElement(xmlParserCtxtPtr ctxt, const CHAR *name)
{
+ xmlParserNodeInfo node_info;
+ xmlNodePtr cur = ctxt->node;
+
#ifdef DEBUG_SAX
- fprintf(stderr, "SAX.endElement(%s)\n", name);
+ if (name == NULL)
+ fprintf(stderr, "SAX.endElement(NULL)\n");
+ else
+ fprintf(stderr, "SAX.endElement(%s)\n", name);
#endif
+
+ /* Capture end position and add node */
+ if (cur != NULL && ctxt->record_info) {
+ node_info.end_pos = ctxt->input->cur - ctxt->input->base;
+ node_info.end_line = ctxt->input->line;
+ node_info.node = cur;
+ xmlParserAddNodeInfo(ctxt, &node_info);
+ }
+
+ /*
+ * end of parsing of this node.
+ */
+ nodePop(ctxt);
}
/**
- * attribute:
+ * reference:
* @ctxt: An XML parser context
- * @name: The attribute name
- * @value: The attribute value
+ * @name: The entity name
*
- * called when an attribute 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.
+ * called when an entity reference is detected.
*/
void
-attribute(xmlParserCtxtPtr ctxt, const CHAR *name, const CHAR *value)
+reference(xmlParserCtxtPtr ctxt, const CHAR *name)
{
+ xmlNodePtr ret;
+
#ifdef DEBUG_SAX
- fprintf(stderr, "SAX.attribute(%s, %s)\n", name, value);
+ fprintf(stderr, "SAX.reference(%s)\n", name);
#endif
+ ret = xmlNewReference(ctxt->myDoc, name);
+ xmlAddChild(ctxt->node, ret);
}
/**
* characters:
* @ctxt: An XML parser context
* @ch: a CHAR string
- * @start: the first char in the string
* @len: the number of CHAR
*
* receiving some chars from the parser.
* Question: how much at a time ???
*/
void
-characters(xmlParserCtxtPtr ctxt, const CHAR *ch, int start, int len)
+characters(xmlParserCtxtPtr ctxt, const CHAR *ch, int len)
{
xmlNodePtr lastChild;
#ifdef DEBUG_SAX
- fprintf(stderr, "SAX.characters(%.30s, %d, %d)\n", ch, start, len);
+ fprintf(stderr, "SAX.characters(%.30s, %d)\n", ch, len);
#endif
/*
* Handle the data if any. If there is no child
@@ -266,12 +585,12 @@
lastChild = xmlGetLastChild(ctxt->node);
if (lastChild == NULL)
- xmlNodeAddContentLen(ctxt->node, &ch[start], len);
+ xmlNodeAddContentLen(ctxt->node, ch, len);
else {
if (xmlNodeIsText(lastChild))
- xmlTextConcat(lastChild, &ch[start], len);
+ xmlTextConcat(lastChild, ch, len);
else {
- lastChild = xmlNewTextLen(&ch[start], len);
+ lastChild = xmlNewTextLen(ch, len);
xmlAddChild(ctxt->node, lastChild);
}
}
@@ -281,17 +600,16 @@
* ignorableWhitespace:
* @ctxt: An XML parser context
* @ch: a CHAR string
- * @start: the first char in the string
* @len: the number of CHAR
*
* receiving some ignorable whitespaces from the parser.
* Question: how much at a time ???
*/
void
-ignorableWhitespace(xmlParserCtxtPtr ctxt, const CHAR *ch, int start, int len)
+ignorableWhitespace(xmlParserCtxtPtr ctxt, const CHAR *ch, int len)
{
#ifdef DEBUG_SAX
- fprintf(stderr, "SAX.ignorableWhitespace(%.30s, %d, %d)\n", ch, start, len);
+ fprintf(stderr, "SAX.ignorableWhitespace(%.30s, %d)\n", ch, len);
#endif
}
@@ -313,19 +631,173 @@
#endif
}
+/**
+ * globalNamespace:
+ * @ctxt: An XML parser context
+ * @href: the namespace associated URN
+ * @prefix: the namespace prefix
+ *
+ * An old global namespace has been parsed.
+ */
+void
+globalNamespace(xmlParserCtxtPtr ctxt, const CHAR *href, const CHAR *prefix)
+{
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.globalNamespace(%s, %s)\n", href, prefix);
+#endif
+ xmlNewGlobalNs(ctxt->myDoc, href, prefix);
+}
+
+/**
+ * setNamespace:
+ * @ctxt: An XML parser context
+ * @name: the namespace prefix
+ *
+ * Set the current element namespace.
+ */
+void
+setNamespace(xmlParserCtxtPtr ctxt, const CHAR *name)
+{
+ xmlNsPtr ns;
+ xmlNodePtr parent;
+
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.setNamespace(%s)\n", name);
+#endif
+ ns = xmlSearchNs(ctxt->myDoc, ctxt->node, name);
+ if (ns == NULL) { /* ctxt->node may not have a parent yet ! */
+ if (ctxt->nodeNr >= 2) {
+ parent = ctxt->nodeTab[ctxt->nodeNr - 2];
+ if (parent != NULL)
+ ns = xmlSearchNs(ctxt->myDoc, parent, name);
+ }
+ }
+ xmlSetNs(ctxt->node, ns);
+}
+
+/**
+ * getNamespace:
+ * @ctxt: An XML parser context
+ *
+ * Get the current element namespace.
+ */
+xmlNsPtr
+getNamespace(xmlParserCtxtPtr ctxt)
+{
+ xmlNsPtr ret;
+
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.getNamespace()\n");
+#endif
+ ret = ctxt->node->ns;
+ return(ret);
+}
+
+/**
+ * checkNamespace:
+ * @ctxt: An XML parser context
+ * @namespace: the namespace to check against
+ *
+ * Check that the current element namespace is the same as the
+ * one read upon parsing.
+ */
+int
+checkNamespace(xmlParserCtxtPtr ctxt, CHAR *namespace)
+{
+ xmlNodePtr cur = ctxt->node;
+
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.checkNamespace(%s)\n", namespace);
+#endif
+
+ /*
+ * Check that the Name in the ETag is the same as in the STag.
+ */
+ if (namespace == NULL) {
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt,
+ "End tags for %s don't hold the namespace %s\n",
+ cur->name, cur->ns->prefix);
+ ctxt->wellFormed = 0;
+ }
+ } else {
+ if ((cur->ns == NULL) || (cur->ns->prefix == NULL)) {
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt,
+ "End tags %s holds a prefix %s not used by the open tag\n",
+ cur->name, namespace);
+ ctxt->wellFormed = 0;
+ } else if (strcmp(namespace, cur->ns->prefix)) {
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt,
+ "Start and End tags for %s don't use the same namespaces: %s and %s\n",
+ cur->name, cur->ns->prefix, namespace);
+ ctxt->wellFormed = 0;
+ } else
+ return(1);
+ }
+ return(0);
+}
+
+/**
+ * namespaceDecl:
+ * @ctxt: An XML parser context
+ * @href: the namespace associated URN
+ * @prefix: the namespace prefix
+ *
+ * A namespace has been parsed.
+ */
+void
+namespaceDecl(xmlParserCtxtPtr ctxt, const CHAR *href, const CHAR *prefix)
+{
+#ifdef DEBUG_SAX
+ if (prefix == NULL)
+ fprintf(stderr, "SAX.namespaceDecl(%s, NULL)\n", href);
+ else
+ fprintf(stderr, "SAX.namespaceDecl(%s, %s)\n", href, prefix);
+#endif
+ xmlNewNs(ctxt->node, href, prefix);
+}
+
+/**
+ * comment:
+ * @ctxt: An XML parser context
+ * @value: the comment content
+ *
+ * A comment has been parsed.
+ */
+void
+comment(xmlParserCtxtPtr ctxt, const CHAR *value)
+{
+#ifdef DEBUG_SAX
+ fprintf(stderr, "SAX.comment(%s)\n", value);
+#endif
+ xmlNewDocComment(ctxt->myDoc, value);
+}
+
xmlSAXHandler xmlDefaultSAXHandler = {
+ internalSubset,
+ isStandalone,
+ hasInternalSubset,
+ hasExternalSubset,
resolveEntity,
+ getEntity,
+ entityDecl,
notationDecl,
+ attributeDecl,
+ elementDecl,
unparsedEntityDecl,
setDocumentLocator,
startDocument,
endDocument,
startElement,
endElement,
- attribute,
+ reference,
characters,
ignorableWhitespace,
processingInstruction,
+ comment,
xmlParserWarning,
xmlParserError,
xmlParserError,
@@ -339,7 +811,15 @@
void
xmlDefaultSAXHandlerInit(void)
{
+ xmlDefaultSAXHandler.internalSubset = internalSubset;
+ xmlDefaultSAXHandler.isStandalone = isStandalone;
+ xmlDefaultSAXHandler.hasInternalSubset = hasInternalSubset;
+ xmlDefaultSAXHandler.hasExternalSubset = hasExternalSubset;
xmlDefaultSAXHandler.resolveEntity = resolveEntity;
+ xmlDefaultSAXHandler.getEntity = getEntity;
+ xmlDefaultSAXHandler.entityDecl = entityDecl;
+ xmlDefaultSAXHandler.attributeDecl = attributeDecl;
+ xmlDefaultSAXHandler.elementDecl = elementDecl;
xmlDefaultSAXHandler.notationDecl = notationDecl;
xmlDefaultSAXHandler.unparsedEntityDecl = unparsedEntityDecl;
xmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
@@ -347,10 +827,11 @@
xmlDefaultSAXHandler.endDocument = endDocument;
xmlDefaultSAXHandler.startElement = startElement;
xmlDefaultSAXHandler.endElement = endElement;
- xmlDefaultSAXHandler.attribute = attribute;
+ xmlDefaultSAXHandler.reference = reference;
xmlDefaultSAXHandler.characters = characters;
xmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
xmlDefaultSAXHandler.processingInstruction = processingInstruction;
+ xmlDefaultSAXHandler.comment = comment;
xmlDefaultSAXHandler.warning = xmlParserWarning;
xmlDefaultSAXHandler.error = xmlParserError;
xmlDefaultSAXHandler.fatalError = xmlParserError;