From dbfd641b78b5a98e790459e13d126e2784a7adeb Mon Sep 17 00:00:00 2001
From: Daniel Veillard
Date: Tue, 28 Dec 1999 16:35:14 +0000
Subject: [PATCH] - Lots of improvements, too long to list here - Push mode for
the XML parser (HTML to come) - XML shell like interface for debug -
improvements on XPath and validation Daniel
---
ChangeLog | 17 +
HTMLparser.c | 22 +-
HTMLtree.c | 11 +-
SAX.c | 16 +-
debugXML.c | 829 +++++++++++++++++++++-
debugXML.h | 94 ++-
doc/xml.html | 5 +-
entities.c | 9 +-
entities.h | 1 +
include/libxml/debugXML.h | 94 ++-
include/libxml/entities.h | 1 +
include/libxml/parser.h | 61 +-
include/libxml/parserInternals.h | 10 +-
include/libxml/tree.h | 3 +
include/libxml/xmlIO.h | 3 +
include/libxml/xmlmemory.h | 4 +-
include/libxml/xpath.h | 3 +
parser.c | 1102 +++++++++++++++++++++++++++---
parser.h | 61 +-
parserInternals.h | 10 +-
testSAX.c | 129 ++--
tester.c | 109 ++-
tree.c | 345 +++++++++-
tree.h | 3 +
valid.c | 68 +-
xmlIO.c | 34 +-
xmlIO.h | 3 +
xmlmemory.c | 45 +-
xmlmemory.h | 4 +-
xpath.c | 84 ++-
xpath.h | 3 +
31 files changed, 2876 insertions(+), 307 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 04d7a0fe..50790ba4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+Tue Dec 28 18:44:22 CET 1999 Daniel Veillard
+
+ * parser.[ch] parserInternals.h: Push parser for XML,
+ seems to work fine now
+ * tester.c debugXML.[ch]: Added an XML shell debug facility and
+ --push for push testing
+ * xpath.[ch] : cleaned up for Shell usage, added missing APIs
+ * testSAX.c: added --push
+ * HTMLtree.[ch] tree.[ch]: new functions for dumping parts of the
+ subtree
+ * xmlIO.[ch] : enriched API + fixes for push mode
+ * entities.[ch]: added the entity content length to the struct.
+ * xmlmemory.[ch]: new API to show the last entries for the shell
+ * valid.c: added required attribute testing
+ * SAX.c: the cdata callback now merge contiguous fragments
+ * HTMLparser.c: cleanup of some macros
+
Wed Dec 22 12:20:53 CET 1999 Daniel Veillard
* parser.c: fix for PIs name starting with xml
diff --git a/HTMLparser.c b/HTMLparser.c
index 7276e7c5..e3a1f723 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -57,8 +57,8 @@
* Generic function for accessing stacks in the Parser Context
*/
-#define PUSH_AND_POP(type, name) \
-int html##name##Push(htmlParserCtxtPtr ctxt, type value) { \
+#define PUSH_AND_POP(scope, type, name) \
+scope int html##name##Push(htmlParserCtxtPtr ctxt, type value) { \
if (ctxt->name##Nr >= ctxt->name##Max) { \
ctxt->name##Max *= 2; \
ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
@@ -72,7 +72,7 @@ int html##name##Push(htmlParserCtxtPtr ctxt, type value) { \
ctxt->name = value; \
return(ctxt->name##Nr++); \
} \
-type html##name##Pop(htmlParserCtxtPtr ctxt) { \
+scope type html##name##Pop(htmlParserCtxtPtr ctxt) { \
type ret; \
if (ctxt->name##Nr < 0) return(0); \
ctxt->name##Nr--; \
@@ -86,8 +86,8 @@ type html##name##Pop(htmlParserCtxtPtr ctxt) { \
return(ret); \
} \
-PUSH_AND_POP(xmlNodePtr, node)
-PUSH_AND_POP(xmlChar*, name)
+PUSH_AND_POP(extern, xmlNodePtr, node)
+PUSH_AND_POP(extern, xmlChar*, name)
/*
* Macros for accessing the content. Those should be used only by the parser,
@@ -2626,11 +2626,11 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) {
}
-/********************************************************************************
- * *
- * Parser contexts handling *
- * *
- ********************************************************************************/
+/************************************************************************
+ * *
+ * Parser contexts handling *
+ * *
+ ************************************************************************/
/**
* xmlInitParserCtxt:
@@ -2665,6 +2665,7 @@ htmlInitParserCtxt(htmlParserCtxtPtr ctxt)
ctxt->version = NULL;
ctxt->encoding = NULL;
ctxt->standalone = -1;
+ ctxt->instate = XML_PARSER_START;
/* Allocate the Node stack */
ctxt->nodeTab = (htmlNodePtr *) xmlMalloc(10 * sizeof(htmlNodePtr));
@@ -2691,6 +2692,7 @@ htmlInitParserCtxt(htmlParserCtxtPtr ctxt)
ctxt->record_info = 0;
ctxt->validate = 0;
ctxt->nbChars = 0;
+ ctxt->checkIndex = 0;
xmlInitNodeInfoSeq(&ctxt->node_seq);
}
diff --git a/HTMLtree.c b/HTMLtree.c
index c84daea5..e6142ae6 100644
--- a/HTMLtree.c
+++ b/HTMLtree.c
@@ -28,6 +28,9 @@
#include "entities.h"
#include "valid.h"
+static void
+htmlDocContentDump(xmlBufferPtr buf, xmlDocPtr cur);
+
/**
* htmlDtdDump:
* @buf: the HTML buffer output
@@ -108,7 +111,7 @@ htmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
}
-static void
+void
htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
/**
* htmlNodeListDump:
@@ -138,7 +141,7 @@ htmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) {
*
* Dump an HTML node, recursive behaviour,children are printed too.
*/
-static void
+void
htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) {
htmlElemDescPtr info;
@@ -149,6 +152,10 @@ htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) {
/*
* Special cases.
*/
+ if (cur->type == XML_HTML_DOCUMENT_NODE) {
+ htmlDocContentDump(buf, (xmlDocPtr) cur);
+ return;
+ }
if (cur->type == HTML_TEXT_NODE) {
if (cur->content != NULL) {
xmlChar *buffer;
diff --git a/SAX.c b/SAX.c
index be5a0abd..19e0da36 100644
--- a/SAX.c
+++ b/SAX.c
@@ -1101,14 +1101,22 @@ void
cdataBlock(void *ctx, const xmlChar *value, int len)
{
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
- xmlNodePtr ret;
+ xmlNodePtr ret, lastChild;
#ifdef DEBUG_SAX
fprintf(stderr, "SAX.pcdata(%.10s, %d)\n", value, len);
#endif
- ret = xmlNewCDataBlock(ctxt->myDoc, value, len);
- xmlAddChild(ctxt->node, ret);
- /* !!!!! merges */
+ lastChild = xmlGetLastChild(ctxt->node);
+#ifdef DEBUG_SAX_TREE
+ fprintf(stderr, "add chars to %s \n", ctxt->node->name);
+#endif
+ if ((lastChild != NULL) &&
+ (lastChild->type == XML_CDATA_SECTION_NODE)) {
+ xmlTextConcat(lastChild, value, len);
+ } else {
+ ret = xmlNewCDataBlock(ctxt->myDoc, value, len);
+ xmlAddChild(ctxt->node, ret);
+ }
}
/*
diff --git a/debugXML.c b/debugXML.c
index 2344bb22..99972ae1 100644
--- a/debugXML.c
+++ b/debugXML.c
@@ -13,9 +13,15 @@
#include "config.h"
#endif
#include
+#ifdef HAVE_STDLIB_H
+#include
+#endif
+#include "xmlmemory.h"
#include "tree.h"
#include "parser.h"
#include "debugXML.h"
+#include "HTMLtree.h"
+#include "HTMLparser.h"
#define IS_BLANK(c) \
(((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
@@ -43,7 +49,7 @@ void xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) {
if (ns->prefix != NULL)
fprintf(output, "namespace %s href=", ns->prefix);
else
- fprintf(output, "default namespace href=", ns->prefix);
+ fprintf(output, "default namespace href=");
xmlDebugDumpString(output, ns->href);
fprintf(output, "\n");
@@ -217,7 +223,7 @@ void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth) {
}
-void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) {
+void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc) {
if (output == NULL) output = stdout;
if (doc == NULL) {
fprintf(output, "DOCUMENT == NULL !\n");
@@ -286,10 +292,21 @@ void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) {
fprintf(output, "standalone=true\n");
if (doc->oldNs != NULL)
xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
- if (doc->root != NULL)
- xmlDebugDumpNodeList(output, doc->root, 1);
}
+void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) {
+ if (output == NULL) output = stdout;
+ if (doc == NULL) {
+ fprintf(output, "DOCUMENT == NULL !\n");
+ return;
+ }
+ xmlDebugDumpDocumentHead(output, doc);
+ if (((doc->type == XML_DOCUMENT_NODE) ||
+ (doc->type == XML_HTML_DOCUMENT_NODE)) &&
+ (doc->root != NULL))
+ xmlDebugDumpNodeList(output, doc->root, 1);
+}
+
void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) {
int i;
xmlEntityPtr cur;
@@ -422,3 +439,807 @@ void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) {
} else
fprintf(output, "No entities in external subset\n");
}
+
+static int xmlLsCountNode(xmlNodePtr node) {
+ int ret = 0;
+ xmlNodePtr list = NULL;
+
+ switch (node->type) {
+ case XML_ELEMENT_NODE:
+ list = node->childs;
+ break;
+ case XML_DOCUMENT_NODE:
+ case XML_HTML_DOCUMENT_NODE:
+ list = ((xmlDocPtr) node)->root;
+ break;
+ case XML_ATTRIBUTE_NODE:
+ list = ((xmlAttrPtr) node)->val;
+ break;
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ case XML_PI_NODE:
+ case XML_COMMENT_NODE:
+ if (node->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+ ret = xmlStrlen(node->content);
+#else
+ ret = xmlBufferLength(node->content);
+#endif
+ }
+ break;
+ case XML_ENTITY_REF_NODE:
+ case XML_DOCUMENT_TYPE_NODE:
+ case XML_ENTITY_NODE:
+ case XML_DOCUMENT_FRAG_NODE:
+ case XML_NOTATION_NODE:
+ ret = 1;
+ break;
+ }
+ for (;list != NULL;ret++)
+ list = list->next;
+ return(ret);
+}
+
+void xmlLsOneNode(FILE *output, xmlNodePtr node) {
+ switch (node->type) {
+ case XML_ELEMENT_NODE:
+ fprintf(output, "-");
+ break;
+ case XML_ATTRIBUTE_NODE:
+ fprintf(output, "a");
+ break;
+ case XML_TEXT_NODE:
+ fprintf(output, "t");
+ break;
+ case XML_CDATA_SECTION_NODE:
+ fprintf(output, "c");
+ break;
+ case XML_ENTITY_REF_NODE:
+ fprintf(output, "e");
+ break;
+ case XML_ENTITY_NODE:
+ fprintf(output, "E");
+ break;
+ case XML_PI_NODE:
+ fprintf(output, "p");
+ break;
+ case XML_COMMENT_NODE:
+ fprintf(output, "c");
+ break;
+ case XML_DOCUMENT_NODE:
+ fprintf(output, "d");
+ break;
+ case XML_HTML_DOCUMENT_NODE:
+ fprintf(output, "h");
+ break;
+ case XML_DOCUMENT_TYPE_NODE:
+ fprintf(output, "T");
+ break;
+ case XML_DOCUMENT_FRAG_NODE:
+ fprintf(output, "F");
+ break;
+ case XML_NOTATION_NODE:
+ fprintf(output, "N");
+ break;
+ default:
+ fprintf(output, "?");
+ }
+ if (node->properties != NULL)
+ fprintf(output, "a");
+ else
+ fprintf(output, "-");
+ if (node->nsDef != NULL)
+ fprintf(output, "n");
+ else
+ fprintf(output, "-");
+
+ fprintf(output, " %8d ", xmlLsCountNode(node));
+
+ switch (node->type) {
+ case XML_ELEMENT_NODE:
+ if (node->name != NULL)
+ fprintf(output, "%s", node->name);
+ break;
+ case XML_ATTRIBUTE_NODE:
+ if (node->name != NULL)
+ fprintf(output, "%s", node->name);
+ break;
+ case XML_TEXT_NODE:
+ if (node->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+ xmlDebugDumpString(output, node->content);
+#else
+ xmlDebugDumpString(output, xmlBufferContent(node->content));
+#endif
+ }
+ break;
+ case XML_CDATA_SECTION_NODE:
+ break;
+ case XML_ENTITY_REF_NODE:
+ if (node->name != NULL)
+ fprintf(output, "%s", node->name);
+ break;
+ case XML_ENTITY_NODE:
+ if (node->name != NULL)
+ fprintf(output, "%s", node->name);
+ break;
+ case XML_PI_NODE:
+ if (node->name != NULL)
+ fprintf(output, "%s", node->name);
+ break;
+ case XML_COMMENT_NODE:
+ break;
+ case XML_DOCUMENT_NODE:
+ break;
+ case XML_HTML_DOCUMENT_NODE:
+ break;
+ case XML_DOCUMENT_TYPE_NODE:
+ break;
+ case XML_DOCUMENT_FRAG_NODE:
+ break;
+ case XML_NOTATION_NODE:
+ break;
+ default:
+ if (node->name != NULL)
+ fprintf(output, "%s", node->name);
+ }
+ fprintf(output, "\n");
+}
+
+/****************************************************************
+ * *
+ * The XML shell related functions *
+ * *
+ ****************************************************************/
+
+/*
+ * TODO: Improvement/cleanups for the XML shell
+ * - allow to shell out an editor on a subpart
+ * - cleanup function registrations (with help) and calling
+ * - provide registration routines
+ */
+
+/**
+ * xmlShellList:
+ * @ctxt: the shell context
+ * @arg: unused
+ * @node: a node
+ * @node2: unused
+ *
+ * Implements the XML shell function "ls"
+ * Does an Unix like listing of the given node (like a directory)
+ *
+ * Returns 0
+ */
+int
+xmlShellList(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
+ xmlNodePtr node2) {
+ xmlNodePtr cur;
+
+ if ((node->type == XML_DOCUMENT_NODE) ||
+ (node->type == XML_HTML_DOCUMENT_NODE)) {
+ cur = ((xmlDocPtr) node)->root;
+ } else if (node->childs != NULL) {
+ cur = node->childs;
+ } else {
+ xmlLsOneNode(stdout, node);
+ return(0);
+ }
+ while (cur != NULL) {
+ xmlLsOneNode(stdout, cur);
+ cur = cur->next;
+ }
+ return(0);
+}
+
+/**
+ * xmlShellDir:
+ * @ctxt: the shell context
+ * @arg: unused
+ * @node: a node
+ * @node2: unused
+ *
+ * Implements the XML shell function "dir"
+ * dumps informations about the node (namespace, attributes, content).
+ *
+ * Returns 0
+ */
+int
+xmlShellDir(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
+ xmlNodePtr node2) {
+ if ((node->type == XML_DOCUMENT_NODE) ||
+ (node->type == XML_HTML_DOCUMENT_NODE)) {
+ xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
+ } else if (node->type == XML_ATTRIBUTE_NODE) {
+ xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
+ } else {
+ xmlDebugDumpOneNode(stdout, node, 0);
+ }
+ return(0);
+}
+
+/**
+ * xmlShellCat:
+ * @ctxt: the shell context
+ * @arg: unused
+ * @node: a node
+ * @node2: unused
+ *
+ * Implements the XML shell function "cat"
+ * dumps the serialization node content (XML or HTML).
+ *
+ * Returns 0
+ */
+int
+xmlShellCat(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
+ xmlNodePtr node2) {
+ xmlElemDump(stdout, ctxt->doc, node);
+ printf("\n");
+ return(0);
+}
+
+/**
+ * xmlShellLoad:
+ * @ctxt: the shell context
+ * @filename: the file name
+ * @node: unused
+ * @node2: unused
+ *
+ * Implements the XML shell function "load"
+ * loads a new document specified by the filename
+ *
+ * Returns 0 or -1 if loading failed
+ */
+int
+xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
+ xmlNodePtr node2) {
+ xmlDocPtr doc;
+ int html = 0;
+
+ if (ctxt->doc != NULL)
+ html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
+
+ if (html) {
+ doc = htmlParseFile(filename, NULL);
+ } else {
+ doc = xmlParseFile(filename);
+ }
+ if (doc != NULL) {
+ if (ctxt->loaded == 1) {
+ xmlFreeDoc(ctxt->doc);
+ }
+ ctxt->loaded = 1;
+ xmlXPathFreeContext(ctxt->pctxt);
+ xmlFree(ctxt->filename);
+ ctxt->doc = doc;
+ ctxt->node = (xmlNodePtr) doc;
+ ctxt->pctxt = xmlXPathNewContext(doc);
+ ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
+ } else
+ return(-1);
+ return(0);
+}
+
+/**
+ * xmlShellWrite:
+ * @ctxt: the shell context
+ * @filename: the file name
+ * @node: a node in the tree
+ * @node2: unused
+ *
+ * Implements the XML shell function "write"
+ * Write the current node to the filename, it saves the serailization
+ * of the subtree under the @node specified
+ *
+ * Returns 0 or -1 in case of error
+ */
+int
+xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
+ xmlNodePtr node2) {
+ if (node == NULL)
+ return(-1);
+ if ((filename == NULL) || (filename[0] == 0)) {
+ fprintf(stderr, "Write command requires a filename argument\n");
+ return(-1);
+ }
+#ifdef W_OK
+ if (access((char *) filename, W_OK)) {
+ fprintf(stderr, "Cannot write to %s\n", filename);
+ return(-1);
+ }
+#endif
+ switch(node->type) {
+ case XML_DOCUMENT_NODE:
+ if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
+ fprintf(stderr, "Failed to write to %s\n", filename);
+ return(-1);
+ }
+ break;
+ case XML_HTML_DOCUMENT_NODE:
+ if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
+ fprintf(stderr, "Failed to write to %s\n", filename);
+ return(-1);
+ }
+ break;
+ default: {
+ FILE *f;
+
+ f = fopen((char *) filename, "w");
+ if (f == NULL) {
+ fprintf(stderr, "Failed to write to %s\n", filename);
+ return(-1);
+ }
+ xmlElemDump(f, ctxt->doc, node);
+ fclose(f);
+ }
+ }
+ return(0);
+}
+
+/**
+ * xmlShellSave:
+ * @ctxt: the shell context
+ * @filename: the file name (optionnal)
+ * @node: unused
+ * @node2: unused
+ *
+ * Implements the XML shell function "save"
+ * Write the current document to the filename, or it's original name
+ *
+ * Returns 0 or -1 in case of error
+ */
+int
+xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
+ xmlNodePtr node2) {
+ if (ctxt->doc == NULL)
+ return(-1);
+ if ((filename == NULL) || (filename[0] == 0))
+ filename = ctxt->filename;
+#ifdef W_OK
+ if (access((char *) filename, W_OK)) {
+ fprintf(stderr, "Cannot save to %s\n", filename);
+ return(-1);
+ }
+#endif
+ switch(ctxt->doc->type) {
+ case XML_DOCUMENT_NODE:
+ if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
+ fprintf(stderr, "Failed to save to %s\n", filename);
+ }
+ break;
+ case XML_HTML_DOCUMENT_NODE:
+ if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
+ fprintf(stderr, "Failed to save to %s\n", filename);
+ }
+ break;
+ default:
+ fprintf(stderr,
+ "To save to subparts of a document use the 'write' command\n");
+ return(-1);
+
+ }
+ return(0);
+}
+
+/**
+ * xmlShellValidate:
+ * @ctxt: the shell context
+ * @dtd: the DTD URI (optionnal)
+ * @node: unused
+ * @node2: unused
+ *
+ * Implements the XML shell function "validate"
+ * Validate the document, if a DTD path is provided, then the validation
+ * is done against the given DTD.
+ *
+ * Returns 0 or -1 in case of error
+ */
+int
+xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node,
+ xmlNodePtr node2) {
+ xmlValidCtxt vctxt;
+ int res = -1;
+
+ vctxt.userData = stderr;
+ vctxt.error = (xmlValidityErrorFunc) fprintf;
+ vctxt.warning = (xmlValidityWarningFunc) fprintf;
+
+ if ((dtd == NULL) || (dtd[0] == 0)) {
+ res = xmlValidateDocument(&vctxt, ctxt->doc);
+ } else {
+ xmlDtdPtr subset;
+
+ subset = xmlParseDTD(NULL, (xmlChar *) dtd);
+ if (subset != NULL) {
+ res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
+
+ xmlFreeDtd(subset);
+ }
+ }
+ return(res);
+}
+
+/**
+ * xmlShellDu:
+ * @ctxt: the shell context
+ * @arg: unused
+ * @tree: a node defining a subtree
+ * @node2: unused
+ *
+ * Implements the XML shell function "du"
+ * show the structure of the subtree under node @tree
+ * If @tree is null, the command works on the current node.
+ *
+ * Returns 0 or -1 in case of error
+ */
+int
+xmlShellDu(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree,
+ xmlNodePtr node2) {
+ xmlNodePtr node;
+ int indent = 0,i;
+
+ if (tree == NULL) return(-1);
+ node = tree;
+ while (node != NULL) {
+ if ((node->type == XML_DOCUMENT_NODE) ||
+ (node->type == XML_HTML_DOCUMENT_NODE)) {
+ printf("/\n");
+ } else if (node->type == XML_ELEMENT_NODE) {
+ for (i = 0;i < indent;i++)
+ printf(" ");
+ printf("%s\n", node->name);
+ } else {
+ }
+
+ /*
+ * Browse the full subtree, deep first
+ */
+
+ if ((node->type == XML_DOCUMENT_NODE) ||
+ (node->type == XML_HTML_DOCUMENT_NODE)) {
+ node = ((xmlDocPtr) node)->root;
+ } else if (node->childs != NULL) {
+ /* deep first */
+ node = node->childs;
+ indent++;
+ } else if ((node != tree) && (node->next != NULL)) {
+ /* then siblings */
+ node = node->next;
+ } else if (node != tree) {
+ /* go up to parents->next if needed */
+ while (node != tree) {
+ if (node->parent != NULL) {
+ node = node->parent;
+ indent--;
+ }
+ if ((node != tree) && (node->next != NULL)) {
+ node = node->next;
+ break;
+ }
+ if (node->parent == NULL) {
+ node = NULL;
+ break;
+ }
+ if (node == tree) {
+ node = NULL;
+ break;
+ }
+ }
+ /* exit condition */
+ if (node == tree)
+ node = NULL;
+ } else
+ node = NULL;
+ }
+ return(0);
+}
+
+/**
+ * xmlShellPwd:
+ * @ctxt: the shell context
+ * @buffer: the output buffer
+ * @tree: a node
+ * @node2: unused
+ *
+ * Implements the XML shell function "pwd"
+ * Show the full path from the root to the node, if needed building
+ * thumblers when similar elements exists at a given ancestor level.
+ * The output is compatible with XPath commands.
+ *
+ * Returns 0 or -1 in case of error
+ */
+int
+xmlShellPwd(xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node,
+ xmlNodePtr node2) {
+ xmlNodePtr cur, tmp, next;
+ char buf[500];
+ char sep;
+ const char *name;
+ int occur = 0;
+
+ buffer[0] = 0;
+ if (node == NULL) return(-1);
+ cur = node;
+ do {
+ name = "";
+ sep= '?';
+ occur = 0;
+ if ((cur->type == XML_DOCUMENT_NODE) ||
+ (cur->type == XML_HTML_DOCUMENT_NODE)) {
+ sep = '/';
+ next = NULL;
+ } else if (cur->type == XML_ELEMENT_NODE) {
+ sep = '/';
+ name = (const char *)cur->name;
+ next = cur->parent;
+
+ /*
+ * Thumbler index computation
+ */
+ tmp = cur->prev;
+ while (tmp != NULL) {
+ if (!xmlStrcmp(cur->name, tmp->name))
+ occur++;
+ tmp = tmp->prev;
+ }
+ if (occur == 0) {
+ tmp = cur->next;
+ while (tmp != NULL) {
+ if (!xmlStrcmp(cur->name, tmp->name))
+ occur++;
+ tmp = tmp->next;
+ }
+ if (occur != 0) occur = 1;
+ } else
+ occur++;
+ } else if (cur->type == XML_ATTRIBUTE_NODE) {
+ sep = '@';
+ name = (const char *) (((xmlAttrPtr) cur)->name);
+ next = ((xmlAttrPtr) cur)->node;
+ } else {
+ next = cur->parent;
+ }
+ if (occur == 0)
+ sprintf(buf, "%c%s%s", sep, name, buffer);
+ else
+ sprintf(buf, "%c%s[%d]%s", sep, name, occur, buffer);
+ strcpy(buffer, buf);
+ cur = next;
+ } while (cur != NULL);
+ return(0);
+}
+
+/**
+ * xmlShell
+ * @doc: the initial document
+ * @filename: the output buffer
+ * @input: the line reading function
+ * @output: the output FILE*
+ *
+ * Implements the XML shell
+ * This allow to load, validate, view, modify and save a document
+ * using a environment similar to a UNIX commandline.
+ */
+void
+xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
+ FILE *output) {
+ char prompt[500] = "/ > ";
+ char *cmdline = NULL;
+ int nbargs;
+ char command[100];
+ char arg[400];
+ xmlShellCtxtPtr ctxt;
+ xmlXPathObjectPtr list;
+
+ if (doc == NULL)
+ return;
+ if (filename == NULL)
+ return;
+ if (input == NULL)
+ return;
+ if (output == NULL)
+ return;
+ ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
+ if (ctxt == NULL)
+ return;
+ ctxt->loaded = 0;
+ ctxt->doc = doc;
+ ctxt->input = input;
+ ctxt->output = output;
+ ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
+ ctxt->node = (xmlNodePtr) ctxt->doc;
+
+ ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
+ if (ctxt->pctxt == NULL) {
+ xmlFree(ctxt);
+ return;
+ }
+ while (1) {
+ if (ctxt->node == (xmlNodePtr) ctxt->doc)
+ sprintf(prompt, "%s > ", "/");
+ else if (ctxt->node->name)
+ sprintf(prompt, "%s > ", ctxt->node->name);
+ else
+ sprintf(prompt, "? > ");
+
+ cmdline = ctxt->input(prompt);
+ if (cmdline == NULL) break;
+
+ command[0] = 0;
+ arg[0] = 0;
+ nbargs = sscanf(cmdline, "%s %s", command, arg);
+
+ if (command[0] == 0) continue;
+ if (!strcmp(command, "exit"))
+ break;
+ if (!strcmp(command, "quit"))
+ break;
+ if (!strcmp(command, "bye"))
+ break;
+ if (!strcmp(command, "validate")) {
+ xmlShellValidate(ctxt, arg, NULL, NULL);
+ } else if (!strcmp(command, "load")) {
+ xmlShellLoad(ctxt, arg, NULL, NULL);
+ } else if (!strcmp(command, "save")) {
+ xmlShellSave(ctxt, arg, NULL, NULL);
+ } else if (!strcmp(command, "write")) {
+ xmlShellWrite(ctxt, arg, NULL, NULL);
+ } else if (!strcmp(command, "free")) {
+ if (arg[0] == 0) {
+ xmlMemShow(stdout, 0);
+ } else {
+ int len = 0;
+ sscanf(arg, "%d", &len);
+ xmlMemShow(stdout, len);
+ }
+ } else if (!strcmp(command, "pwd")) {
+ char dir[500];
+ if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
+ printf("%s\n", dir);
+ } else if (!strcmp(command, "du")) {
+ xmlShellDu(ctxt, NULL, ctxt->node, NULL);
+ } else if ((!strcmp(command, "ls")) ||
+ (!strcmp(command, "dir"))) {
+ int dir = (!strcmp(command, "dir"));
+ if (arg[0] == 0) {
+ if (dir)
+ xmlShellDir(ctxt, NULL, ctxt->node, NULL);
+ else
+ xmlShellList(ctxt, NULL, ctxt->node, NULL);
+ } else {
+ ctxt->pctxt->node = ctxt->node;
+ if (ctxt->pctxt->nodelist != NULL)
+ xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
+ ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
+ list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
+ if (list != NULL) {
+ switch (list->type) {
+ case XPATH_UNDEFINED:
+ fprintf(stderr, "%s: no such node\n", arg);
+ break;
+ case XPATH_NODESET: {
+ int i;
+
+ for (i = 0;i < list->nodesetval->nodeNr;i++) {
+ if (dir)
+ xmlShellDir(ctxt, NULL,
+ list->nodesetval->nodeTab[i], NULL);
+ else
+ xmlShellList(ctxt, NULL,
+ list->nodesetval->nodeTab[i], NULL);
+ }
+ break;
+ }
+ case XPATH_BOOLEAN:
+ fprintf(stderr, "%s is a Boolean\n", arg);
+ break;
+ case XPATH_NUMBER:
+ fprintf(stderr, "%s is a number\n", arg);
+ break;
+ case XPATH_STRING:
+ fprintf(stderr, "%s is a string\n", arg);
+ break;
+ }
+ xmlXPathFreeNodeSetList(list);
+ } else {
+ fprintf(stderr, "%s: no such node\n", arg);
+ }
+ if (ctxt->pctxt->nodelist != NULL)
+ xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
+ ctxt->pctxt->nodelist = NULL;
+ }
+ } else if (!strcmp(command, "cd")) {
+ if (arg[0] == 0) {
+ ctxt->node = (xmlNodePtr) ctxt->doc;
+ } else {
+ ctxt->pctxt->node = ctxt->node;
+ if (ctxt->pctxt->nodelist != NULL)
+ xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
+ ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
+ list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
+ if (list != NULL) {
+ switch (list->type) {
+ case XPATH_UNDEFINED:
+ fprintf(stderr, "%s: no such node\n", arg);
+ break;
+ case XPATH_NODESET:
+ if (list->nodesetval->nodeNr == 1) {
+ ctxt->node = list->nodesetval->nodeTab[0];
+ } else
+ fprintf(stderr, "%s is a %d Node Set\n",
+ arg, list->nodesetval->nodeNr);
+ break;
+ case XPATH_BOOLEAN:
+ fprintf(stderr, "%s is a Boolean\n", arg);
+ break;
+ case XPATH_NUMBER:
+ fprintf(stderr, "%s is a number\n", arg);
+ break;
+ case XPATH_STRING:
+ fprintf(stderr, "%s is a string\n", arg);
+ break;
+ }
+ xmlXPathFreeNodeSetList(list);
+ } else {
+ fprintf(stderr, "%s: no such node\n", arg);
+ }
+ if (ctxt->pctxt->nodelist != NULL)
+ xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
+ ctxt->pctxt->nodelist = NULL;
+ }
+ } else if (!strcmp(command, "cat")) {
+ if (arg[0] == 0) {
+ xmlShellCat(ctxt, NULL, ctxt->node, NULL);
+ } else {
+ ctxt->pctxt->node = ctxt->node;
+ if (ctxt->pctxt->nodelist != NULL)
+ xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
+ ctxt->pctxt->nodelist = xmlXPathNodeSetCreate(ctxt->node);
+ list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
+ if (list != NULL) {
+ switch (list->type) {
+ case XPATH_UNDEFINED:
+ fprintf(stderr, "%s: no such node\n", arg);
+ break;
+ case XPATH_NODESET: {
+ int i;
+
+ for (i = 0;i < list->nodesetval->nodeNr;i++) {
+ if (i > 0) printf(" -------\n");
+ xmlShellCat(ctxt, NULL,
+ list->nodesetval->nodeTab[i], NULL);
+ }
+ break;
+ }
+ case XPATH_BOOLEAN:
+ fprintf(stderr, "%s is a Boolean\n", arg);
+ break;
+ case XPATH_NUMBER:
+ fprintf(stderr, "%s is a number\n", arg);
+ break;
+ case XPATH_STRING:
+ fprintf(stderr, "%s is a string\n", arg);
+ break;
+ }
+ xmlXPathFreeNodeSetList(list);
+ } else {
+ fprintf(stderr, "%s: no such node\n", arg);
+ }
+ if (ctxt->pctxt->nodelist != NULL)
+ xmlXPathFreeNodeSet(ctxt->pctxt->nodelist);
+ ctxt->pctxt->nodelist = NULL;
+ }
+ } else {
+ fprintf(stderr, "Unknown command %s\n", command);
+ }
+ free(cmdline); /* not xmlFree here ! */
+ }
+ xmlXPathFreeContext(ctxt->pctxt);
+ if (ctxt->loaded) {
+ xmlFreeDoc(ctxt->doc);
+ }
+ xmlFree(ctxt);
+ if (cmdline != NULL)
+ free(cmdline); /* not xmlFree here ! */
+}
+
diff --git a/debugXML.h b/debugXML.h
index 9c77496e..8774f0bd 100644
--- a/debugXML.h
+++ b/debugXML.h
@@ -7,19 +7,97 @@
#ifndef __DEBUG_XML__
#define __DEBUG_XML__
+#include
#include "tree.h"
+#include "xpath.h"
#ifdef __cplusplus
extern "C" {
#endif
-extern void xmlDebugDumpString(FILE *output, const xmlChar *str);
-extern void xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth);
-extern void xmlDebugDumpAttrList(FILE *output, xmlAttrPtr attr, int depth);
-extern void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth);
-extern void xmlDebugDumpNode(FILE *output, xmlNodePtr node, int depth);
-extern void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth);
-extern void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc);
-extern void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc);
+
+/*
+ * The standard Dump routines
+ */
+void xmlDebugDumpString (FILE *output,
+ const xmlChar *str);
+void xmlDebugDumpAttr (FILE *output,
+ xmlAttrPtr attr,
+ int depth);
+void xmlDebugDumpAttrList (FILE *output,
+ xmlAttrPtr attr,
+ int depth);
+void xmlDebugDumpOneNode (FILE *output,
+ xmlNodePtr node,
+ int depth);
+void xmlDebugDumpNode (FILE *output,
+ xmlNodePtr node,
+ int depth);
+void xmlDebugDumpNodeList (FILE *output,
+ xmlNodePtr node,
+ int depth);
+void xmlDebugDumpDocumentHead(FILE *output,
+ xmlDocPtr doc);
+void xmlDebugDumpDocument (FILE *output,
+ xmlDocPtr doc);
+void xmlDebugDumpEntities (FILE *output,
+ xmlDocPtr doc);
+void xmlLsOneNode (FILE *output,
+ xmlNodePtr node);
+
+/****************************************************************
+ * *
+ * The XML shell related structures and functions *
+ * *
+ ****************************************************************/
+
+/**
+ * xmlShellReadlineFunc:
+ * @prompt: a string prompt
+ *
+ * This is a generic signature for the XML shell input function
+ *
+ * Returns a string which will be freed by the Shell
+ */
+typedef char * (* xmlShellReadlineFunc)(char *prompt);
+
+/*
+ * The shell context itself
+ * TODO: add the defined function tables.
+ */
+typedef struct xmlShellCtxt {
+ char *filename;
+ xmlDocPtr doc;
+ xmlNodePtr node;
+ xmlXPathContextPtr pctxt;
+ int loaded;
+ FILE *output;
+ xmlShellReadlineFunc input;
+} xmlShellCtxt, *xmlShellCtxtPtr;
+
+/**
+ * xmlShellCmd:
+ * @ctxt: a shell context
+ * @arg: a string argument
+ * @node: a first node
+ * @node2: a second node
+ *
+ * This is a generic signature for the XML shell functions
+ *
+ * Returns an int, negative returns indicating errors
+ */
+typedef int (* xmlShellCmd) (xmlShellCtxtPtr ctxt,
+ char *arg,
+ xmlNodePtr node,
+ xmlNodePtr node2);
+
+/*
+ * The Shell interface.
+ */
+void xmlShell (xmlDocPtr doc,
+ char *filename,
+ xmlShellReadlineFunc input,
+ FILE *output);
+
#ifdef __cplusplus
}
#endif
diff --git a/doc/xml.html b/doc/xml.html
index 40d6e0c3..8bd76392 100644
--- a/doc/xml.html
+++ b/doc/xml.html
@@ -128,6 +128,9 @@ for really accurate description
- working on HTML and XML links recognition layers, get in touch with me
if you want to test those.
+ - a Push interface for the XML parser
+ - an shell like interface to the document tree (try tester --shell :-)
+ - lots of bug fixes and improvement added over XMas hollidays
1.8.2: Dec 21 1999
@@ -901,6 +904,6 @@ base under gnome-xml/example
Daniel Veillard
-$Id: xml.html,v 1.16 1997/01/04 02:49:42 veillard Exp $
+$Id: xml.html,v 1.17 1999/12/21 15:35:27 veillard Exp $