📄 sax2.c
字号:
/*
* SAX2.c : Default SAX2 handler to build a tree.
*
* See Copyright for the status of this software.
*
* Daniel Veillard <daniel@veillard.com>
*/
#define IN_LIBXML
#include "libxml.h"
#include <stdlib.h>
#include <string.h>
#include <libxml/xmlmemory.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
#include <libxml/valid.h>
#include <libxml/entities.h>
#include <libxml/xmlerror.h>
#include <libxml/debugXML.h>
#include <libxml/xmlIO.h>
#include <libxml/SAX.h>
#include <libxml/uri.h>
#include <libxml/valid.h>
#include <libxml/HTMLtree.h>
#include <libxml/globals.h>
/* #define DEBUG_SAX2 */
/* #define DEBUG_SAX2_TREE */
/**
* TODO:
*
* macro to flag unimplemented blocks
* XML_CATALOG_PREFER user env to select between system/public prefered
* option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
*> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
*> values "system" and "public". I have made the default be "system" to
*> match yours.
*/
#define TODO \
xmlGenericError(xmlGenericErrorContext, \
"Unimplemented block at %s:%d\n", \
__FILE__, __LINE__);
/*
* xmlSAX2ErrMemory:
* @ctxt: an XML validation parser context
* @msg: a string to accompany the error message
*/
static void
xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, const char *msg) {
if (ctxt != NULL) {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData, "%s: out of memory\n", msg);
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
}
}
/**
* xmlValidError:
* @ctxt: an XML validation parser context
* @error: the error number
* @msg: the error message
* @str1: extra data
* @str2: extra data
*
* Handle a validation error
*/
static void
xmlErrValid(xmlParserCtxtPtr ctxt, xmlParserErrors error,
const char *msg, const char *str1, const char *str2)
{
xmlStructuredErrorFunc schannel = NULL;
if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
(ctxt->instate == XML_PARSER_EOF))
return;
if (ctxt != NULL) {
ctxt->errNo = error;
if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC))
schannel = ctxt->sax->serror;
}
__xmlRaiseError(schannel,
ctxt->vctxt.error, ctxt->vctxt.userData,
ctxt, NULL, XML_FROM_DTD, error,
XML_ERR_ERROR, NULL, 0, (const char *) str1,
(const char *) str2, NULL, 0, 0,
msg, (const char *) str1, (const char *) str2);
if (ctxt != NULL)
ctxt->valid = 0;
}
/**
* xmlFatalErrMsg:
* @ctxt: an XML parser context
* @error: the error number
* @msg: the error message
* @str1: an error string
* @str2: an error string
*
* Handle a fatal parser error, i.e. violating Well-Formedness constraints
*/
static void
xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
const char *msg, const xmlChar *str1, const xmlChar *str2)
{
if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
(ctxt->instate == XML_PARSER_EOF))
return;
if (ctxt != NULL)
ctxt->errNo = error;
__xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error,
XML_ERR_FATAL, NULL, 0,
(const char *) str1, (const char *) str2,
NULL, 0, 0, msg, str1, str2);
if (ctxt != NULL) {
ctxt->wellFormed = 0;
ctxt->valid = 0;
if (ctxt->recovery == 0)
ctxt->disableSAX = 1;
}
}
/**
* xmlWarnMsg:
* @ctxt: an XML parser context
* @error: the error number
* @msg: the error message
* @str1: an error string
* @str2: an error string
*
* Handle a parser warning
*/
static void
xmlWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
const char *msg, const xmlChar *str1)
{
if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
(ctxt->instate == XML_PARSER_EOF))
return;
if (ctxt != NULL)
ctxt->errNo = error;
__xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error,
XML_ERR_WARNING, NULL, 0,
(const char *) str1, NULL,
NULL, 0, 0, msg, str1);
}
/**
* xmlNsErrMsg:
* @ctxt: an XML parser context
* @error: the error number
* @msg: the error message
* @str1: an error string
* @str2: an error string
*
* Handle a namespace error
*/
static void
xmlNsErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
const char *msg, const xmlChar *str1, const xmlChar *str2)
{
if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
(ctxt->instate == XML_PARSER_EOF))
return;
if (ctxt != NULL)
ctxt->errNo = error;
__xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error,
XML_ERR_ERROR, NULL, 0,
(const char *) str1, (const char *) str2,
NULL, 0, 0, msg, str1, str2);
}
/**
* xmlNsWarnMsg:
* @ctxt: an XML parser context
* @error: the error number
* @msg: the error message
* @str1: an error string
*
* Handle a namespace warning
*/
static void
xmlNsWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
const char *msg, const xmlChar *str1, const xmlChar *str2)
{
if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
(ctxt->instate == XML_PARSER_EOF))
return;
if (ctxt != NULL)
ctxt->errNo = error;
__xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error,
XML_ERR_WARNING, NULL, 0,
(const char *) str1, (const char *) str2,
NULL, 0, 0, msg, str1, str2);
}
/**
* xmlSAX2GetPublicId:
* @ctx: the user data (XML parser context)
*
* Provides the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
*
* Returns a xmlChar *
*/
const xmlChar *
xmlSAX2GetPublicId(void *ctx ATTRIBUTE_UNUSED)
{
/* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
return(NULL);
}
/**
* xmlSAX2GetSystemId:
* @ctx: the user data (XML parser context)
*
* Provides the system ID, basically URL or filename e.g.
* http://www.sgmlsource.com/dtds/memo.dtd
*
* Returns a xmlChar *
*/
const xmlChar *
xmlSAX2GetSystemId(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctx == NULL) || (ctxt->input == NULL)) return(0);
return((const xmlChar *) ctxt->input->filename);
}
/**
* xmlSAX2GetLineNumber:
* @ctx: the user data (XML parser context)
*
* Provide the line number of the current parsing point.
*
* Returns an int
*/
int
xmlSAX2GetLineNumber(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctx == NULL) || (ctxt->input == NULL)) return(0);
return(ctxt->input->line);
}
/**
* xmlSAX2GetColumnNumber:
* @ctx: the user data (XML parser context)
*
* Provide the column number of the current parsing point.
*
* Returns an int
*/
int
xmlSAX2GetColumnNumber(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctx == NULL) || (ctxt->input == NULL)) return(0);
return(ctxt->input->col);
}
/**
* xmlSAX2IsStandalone:
* @ctx: the user data (XML parser context)
*
* Is this document tagged standalone ?
*
* Returns 1 if true
*/
int
xmlSAX2IsStandalone(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctx == NULL) || (ctxt->myDoc == NULL)) return(0);
return(ctxt->myDoc->standalone == 1);
}
/**
* xmlSAX2HasInternalSubset:
* @ctx: the user data (XML parser context)
*
* Does this document has an internal subset
*
* Returns 1 if true
*/
int
xmlSAX2HasInternalSubset(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctxt == NULL) || (ctxt->myDoc == NULL)) return(0);
return(ctxt->myDoc->intSubset != NULL);
}
/**
* xmlSAX2HasExternalSubset:
* @ctx: the user data (XML parser context)
*
* Does this document has an external subset
*
* Returns 1 if true
*/
int
xmlSAX2HasExternalSubset(void *ctx)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if ((ctxt == NULL) || (ctxt->myDoc == NULL)) return(0);
return(ctxt->myDoc->extSubset != NULL);
}
/**
* xmlSAX2InternalSubset:
* @ctx: the user data (XML parser context)
* @name: the root element name
* @ExternalID: the external ID
* @SystemID: the SYSTEM ID (e.g. filename or URL)
*
* Callback on internal subset declaration.
*/
void
xmlSAX2InternalSubset(void *ctx, const xmlChar *name,
const xmlChar *ExternalID, const xmlChar *SystemID)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
xmlDtdPtr dtd;
if (ctx == NULL) return;
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2InternalSubset(%s, %s, %s)\n",
name, ExternalID, SystemID);
#endif
if (ctxt->myDoc == NULL)
return;
dtd = xmlGetIntSubset(ctxt->myDoc);
if (dtd != NULL) {
if (ctxt->html)
return;
xmlUnlinkNode((xmlNodePtr) dtd);
xmlFreeDtd(dtd);
ctxt->myDoc->intSubset = NULL;
}
ctxt->myDoc->intSubset =
xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
if (ctxt->myDoc->intSubset == NULL)
xmlSAX2ErrMemory(ctxt, "xmlSAX2InternalSubset");
}
/**
* xmlSAX2ExternalSubset:
* @ctx: the user data (XML parser context)
* @name: the root element name
* @ExternalID: the external ID
* @SystemID: the SYSTEM ID (e.g. filename or URL)
*
* Callback on external subset declaration.
*/
void
xmlSAX2ExternalSubset(void *ctx, const xmlChar *name,
const xmlChar *ExternalID, const xmlChar *SystemID)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
if (ctx == NULL) return;
#ifdef DEBUG_SAX
xmlGenericError(xmlGenericErrorContext,
"SAX.xmlSAX2ExternalSubset(%s, %s, %s)\n",
name, ExternalID, SystemID);
#endif
if (((ExternalID != NULL) || (SystemID != NULL)) &&
(((ctxt->validate) || (ctxt->loadsubset != 0)) &&
(ctxt->wellFormed && ctxt->myDoc))) {
/*
* Try to fetch and parse the external subset.
*/
xmlParserInputPtr oldinput;
int oldinputNr;
int oldinputMax;
xmlParserInputPtr *oldinputTab;
xmlParserInputPtr input = NULL;
xmlCharEncoding enc;
int oldcharset;
/*
* Ask the Entity resolver to load the damn thing
*/
if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID,
SystemID);
if (input == NULL) {
return;
}
xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID);
/*
* make sure we won't destroy the main document context
*/
oldinput = ctxt->input;
oldinputNr = ctxt->inputNr;
oldinputMax = ctxt->inputMax;
oldinputTab = ctxt->inputTab;
oldcharset = ctxt->charset;
ctxt->inputTab = (xmlParserInputPtr *)
xmlMalloc(5 * sizeof(xmlParserInputPtr));
if (ctxt->inputTab == NULL) {
xmlSAX2ErrMemory(ctxt, "xmlSAX2ExternalSubset");
ctxt->input = oldinput;
ctxt->inputNr = oldinputNr;
ctxt->inputMax = oldinputMax;
ctxt->inputTab = oldinputTab;
ctxt->charset = oldcharset;
return;
}
ctxt->inputNr = 0;
ctxt->inputMax = 5;
ctxt->input = NULL;
xmlPushInput(ctxt, input);
/*
* On the fly encoding conversion if needed
*/
if (ctxt->input->length >= 4) {
enc = xmlDetectCharEncoding(ctxt->input->cur, 4);
xmlSwitchEncoding(ctxt, enc);
}
if (input->filename == NULL)
input->filename = (char *) xmlCanonicPath(SystemID);
input->line = 1;
input->col = 1;
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(ctxt, ExternalID, SystemID);
/*
* Free up the external entities
*/
while (ctxt->inputNr > 1)
xmlPopInput(ctxt);
xmlFreeInputStream(ctxt->input);
xmlFree(ctxt->inputTab);
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -