File:  [Public] / XML / SAX.c
Revision 1.5: download - view: text, annotated - select for diffs
Mon Oct 26 01:38:59 1998 UTC (25 years, 7 months ago) by daniel
Branches: MAIN
CVS tags: HEAD
Update from Gnome development, entity support added, DOM conformance, Daniel.

/*
 * SAX.c : Default SAX handler to build a tree.
 *
 * Daniel Veillard <Daniel.Veillard@w3.org>
 */

#include <stdio.h>
#include <stdlib.h>
#include "tree.h"
#include "parser.h"
#include "entities.h"
#include "error.h"

/* #define DEBUG_SAX */

/**
 * getPublicId:
 * @ctxt:  An XML parser context
 *
 * Return the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
 *
 * return values: a CHAR *
 */
const CHAR *
getPublicId(xmlParserCtxtPtr ctxt)
{
    return(NULL);
}

/**
 * getSystemId:
 * @ctxt:  An XML parser context
 *
 * Return the system ID, basically URI or filename e.g.
 * http://www.sgmlsource.com/dtds/memo.dtd
 *
 * return values: a CHAR *
 */
const CHAR *
getSystemId(xmlParserCtxtPtr ctxt)
{
    return(ctxt->input->filename); 
}

/**
 * getLineNumber:
 * @ctxt:  An XML parser context
 *
 * Return the line number of the current parsing point.
 *
 * return values: an int
 */
int
getLineNumber(xmlParserCtxtPtr ctxt)
{
    return(ctxt->input->line);
}

/**
 * getColumnNumber:
 * @ctxt:  An XML parser context
 *
 * Return the column number of the current parsing point.
 *
 * return values: an int
 */
int
getColumnNumber(xmlParserCtxtPtr ctxt)
{
    return(ctxt->input->col);
}

/*
 * The default SAX Locator.
 */

xmlSAXLocator xmlDefaultSAXLocator = {
    getPublicId, getSystemId, getLineNumber, getColumnNumber
};

/**
 * resolveEntity:
 * @ctxt:  An XML parser context
 * @publicId: The public ID of the entity
 * @systemId: The system ID of the entity
 *
 * Special entity resolver, better left to the parser, it has
 * more context than the application layer.
 * The default behaviour is to NOT resolve the entities, in that case
 * the ENTITY_REF nodes are built in the structure (and the parameter
 * values). However the "standard" entities are resoled except '&amp;'
 *
 * return values: an int
 */
xmlParserInputPtr
resolveEntity(xmlParserCtxtPtr ctxt, const CHAR *publicId, const CHAR *systemId)
{
    xmlEntityPtr entity;
    xmlParserInputPtr input;

#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.resolveEntity(%s, %s)\n", publicId, systemId);
#endif

    entity = xmlGetPredefinedEntity(systemId);
    if (entity != NULL) {
        /*
	 * Avoid some madness with the '&amp;'
	 */
        if (entity->content[0] == '&') 
	    return(NULL);
        input = xmlNewEntityInputStream(ctxt, entity);
	return(input);
    }
    /*
     * If we can get the content, push the entity content
     * as the next input stream.
    entity = xmlGetDocEntity(ctxt->doc, systemId);
    if (entity == NULL) {
	xmlParserWarning(ctxt,
	     "xmlParseEntityRef: &%s; not found\n", name);
    }
    else {
	switch (entity->type) {
	    case XML_INTERNAL_PARAMETER_ENTITY:
	    case XML_EXTERNAL_PARAMETER_ENTITY:
		xmlParserError(ctxt,
    "internal: xmlGetDtdEntity returned a general entity\n");
		break;
	    case XML_INTERNAL_GENERAL_ENTITY:
		if (inLine)
		    ret = entity->content;
		else
		    xmlHandleEntity(ctxt, entity);
		break;
	    case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
	    case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
		xmlParserWarning(ctxt,
"xmlParseEntityRef: external entity &%s; not supported\n",
				 name);
		break;
	    default:
		xmlParserError(ctxt, 
	"internal: xmlParseEntityRef: unknown entity type %d\n",
			       entity->type);
	}
    }
     */
    return(NULL);
}

/**
 * notationDecl:
 * @ctxt:  An XML parser context
 * @name: The name of the notation
 * @publicId: The public ID of the entity
 * @systemId: The system ID of the entity
 *
 * What to do when a notation declaration has been parsed.
 * TODO Not handled currently.
 *
 * return values: 
 */
void
notationDecl(xmlParserCtxtPtr ctxt, const CHAR *name,
	     const CHAR *publicId, const CHAR *systemId)
{
#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.notationDecl(%s, %s, %s)\n", name, publicId, systemId);
#endif
}

/**
 * unparsedEntityDecl:
 * @ctxt:  An XML parser context
 * @name: The name of the entity
 * @publicId: The public ID of the entity
 * @systemId: The system ID of the entity
 * @notationName: the name of the notation
 *
 * What to do when an unparsed entity declaration is parsed
 * TODO Create an Entity node.
 *
 * return values: 
 */
void
unparsedEntityDecl(xmlParserCtxtPtr ctxt, const CHAR *name,
		   const CHAR *publicId, const CHAR *systemId,
		   const CHAR *notationName)
{
#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
            name, publicId, systemId, notationName);
#endif
}

/**
 * setDocumentLocator:
 * @ctxt:  An XML parser context
 * @loc: A SAX Locator
 *
 * Receive the document locator at startup, actually xmlDefaultSAXLocator
 * Everything is available on the context, so this is useless in our case.
 *
 * return values: 
 */
void
setDocumentLocator(xmlParserCtxtPtr ctxt, xmlSAXLocatorPtr loc)
{
#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.setDocumentLocator()\n");
#endif
}

/**
 * startDocument:
 * @ctxt:  An XML parser context
 *
 * called when the document start being processed.
 *
 * return values: 
 */
void
startDocument(xmlParserCtxtPtr ctxt)
{
#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.startDocument()\n");
#endif
}

/**
 * endDocument:
 * @ctxt:  An XML parser context
 *
 * called when the document end has been detected.
 *
 * return values: 
 */
void
endDocument(xmlParserCtxtPtr ctxt)
{
#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.endDocument()\n");
#endif
}

/**
 * startElement:
 * @ctxt:  An XML parser context
 * @name:  The element name
 *
 * called when an opening tag has been processed.
 * TODO We currently have a small pblm with the arguments ...
 *
 * return values: 
 */
void
startElement(xmlParserCtxtPtr ctxt, const CHAR *name)
{
    xmlNodePtr parent;

#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.startElement(%s)\n", name);
#endif
    if (ctxt->nodeNr < 2) return;
    parent = ctxt->nodeTab[ctxt->nodeNr - 2];
    if (parent != NULL)
	xmlAddChild(parent, ctxt->node);
    
}

/**
 * endElement:
 * @ctxt:  An XML parser context
 * @name:  The element name
 *
 * called when the end of an element has been detected.
 *
 * return values: 
 */
void
endElement(xmlParserCtxtPtr ctxt, const CHAR *name)
{
#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.endElement(%s)\n", name);
#endif
}

/**
 * attribute:
 * @ctxt:  An XML parser context
 * @name:  The attribute name
 * @value:  The attribute value
 *
 * 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.
 *
 * return values: 
 */
void
attribute(xmlParserCtxtPtr ctxt, const CHAR *name, const CHAR *value)
{
#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.attribute(%s, %s)\n", name, value);
#endif
    xmlNewProp(ctxt->node, name, value);
}

/**
 * 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 ???
 *
 * return values: 
 */
void
characters(xmlParserCtxtPtr ctxt, const CHAR *ch, int start, int len)
{
    xmlNodePtr lastChild;

#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.characters(%.30s, %d, %d)\n", ch, start, len);
#endif
    /*
     * Handle the data if any. If there is no child
     * add it as content, otherwise if the last child is text,
     * concatenate it, else create a new node of type text.
     */

    lastChild = xmlGetLastChild(ctxt->node);
    if (lastChild == NULL)
	xmlNodeAddContentLen(ctxt->node, &ch[start], len);
    else {
	if (xmlNodeIsText(lastChild))
	    xmlTextConcat(lastChild, &ch[start], len);
	else {
	    lastChild = xmlNewTextLen(&ch[start], len);
	    xmlAddChild(ctxt->node, lastChild);
	}
    }
}

/**
 * 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 ???
 *
 * return values: 
 */
void
ignorableWhitespace(xmlParserCtxtPtr ctxt, const CHAR *ch, int start, int len)
{
#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.ignorableWhitespace(%.30s, %d, %d)\n", ch, start, len);
#endif
}

/**
 * processingInstruction:
 * @ctxt:  An XML parser context
 * @target:  the target name
 * @data: the PI data's
 * @len: the number of CHAR
 *
 * A processing instruction has been parsed.
 *
 * return values: 
 */
void
processingInstruction(xmlParserCtxtPtr ctxt, const CHAR *target,
                      const CHAR *data)
{
#ifdef DEBUG_SAX
    fprintf(stderr, "SAX.processingInstruction(%s, %s)\n", target, data);
#endif
}

xmlSAXHandler xmlDefaultSAXHandler = {
    resolveEntity,
    notationDecl,
    unparsedEntityDecl,
    setDocumentLocator,
    startDocument,
    endDocument,
    startElement,
    endElement,
    attribute,
    characters,
    ignorableWhitespace,
    processingInstruction,
    xmlParserWarning,
    xmlParserError,
    xmlParserError,
};

/**
 * xmlDefaultSAXHandlerInit:
 *
 * Initialize the default SAX handler
 */
void
xmlDefaultSAXHandlerInit(void)
{
    xmlDefaultSAXHandler.resolveEntity = resolveEntity;
    xmlDefaultSAXHandler.notationDecl = notationDecl;
    xmlDefaultSAXHandler.unparsedEntityDecl = unparsedEntityDecl;
    xmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
    xmlDefaultSAXHandler.startDocument = startDocument;
    xmlDefaultSAXHandler.endDocument = endDocument;
    xmlDefaultSAXHandler.startElement = startElement;
    xmlDefaultSAXHandler.endElement = endElement;
    xmlDefaultSAXHandler.attribute = attribute;
    xmlDefaultSAXHandler.characters = characters;
    xmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
    xmlDefaultSAXHandler.processingInstruction = processingInstruction;
    xmlDefaultSAXHandler.warning = xmlParserWarning;
    xmlDefaultSAXHandler.error = xmlParserError;
    xmlDefaultSAXHandler.fatalError = xmlParserError;
}

Webmaster