Commit 7899c5c5 authored by Daniel Veillard's avatar Daniel Veillard

adding XInclude support to the reader interface. Lot of testing of the

* xinclude.c xmlreader.c include/libxml/xinclude.h: adding XInclude
  support to the reader interface. Lot of testing of the walker,
  various bug fixes.
* xmllint.c: added --walker and made sure --xinclude --stream --debug
  works as expected
* Makefile.am result/dtd11.rdr result/ent6.rdr test/dtd11 test/ent6
  result/XInclude/*.rdr: added regression tests for the walker and
  XInclude xmlReader support, had to slightly change a couple of tests
  because the walker can't distinguish <foo/> from <foo></foo>
Daniel
parent 254b1260
Mon Nov 3 13:26:32 CET 2003 Daniel Veillard <daniel@veillard.com>
* xinclude.c xmlreader.c include/libxml/xinclude.h: adding XInclude
support to the reader interface. Lot of testing of the walker,
various bug fixes.
* xmllint.c: added --walker and made sure --xinclude --stream --debug
works as expected
* Makefile.am result/dtd11.rdr result/ent6.rdr test/dtd11 test/ent6
result/XInclude/*.rdr: added regression tests for the walker and
XInclude xmlReader support, had to slightly change a couple of tests
because the walker can't distinguish <foo/> from <foo></foo>
Sat Nov 1 17:42:27 CET 2003 Daniel Veillard <daniel@veillard.com>
* tree.c nanohttp.c threads.c: second BeOS patch from
......
......@@ -414,6 +414,22 @@ XIncludetests : xmllint$(EXEEXT)
if [ -n "$$log" ] ; then echo $$name result ; echo $$log ; fi ; \
rm result.$$name ; \
fi ; fi ; done)
@(echo > .memdump)
@echo "## XInclude xmlReader regression tests"
-@(for i in $(srcdir)/test/XInclude/docs/* ; do \
name=`basename $$i`; \
if [ ! -d $$i ] ; then \
if [ ! -f $(srcdir)/result/XInclude/$$name.rdr ] ; then \
echo New test file $$name ; \
$(CHECKER) $(top_builddir)/xmllint --nowarning --xinclude --walker --debug $$i > $(srcdir)/result/XInclude/$$name.rdr ; \
grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0";\
else \
log=`$(CHECKER) $(top_builddir)/xmllint --nowarning --xinclude --stream --debug $$i 2>&1 > result.$$name | grep -v 'failed to load external entity' ; \
grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0";\
diff $(srcdir)/result/XInclude/$$name.rdr result.$$name` ; \
if [ -n "$$log" ] ; then echo $$name result ; echo $$log ; fi ; \
rm result.$$name ; \
fi ; fi ; done)
Scripttests : xmllint$(EXEEXT)
@(echo > .memdump)
......@@ -547,7 +563,22 @@ Readertests : xmllint$(EXEEXT)
if [ -n "$$log" ] ; then echo $$name result ; echo $$log ; fi ; \
rm result.$$name ; \
fi ; fi ; done)
@(echo > .memdump)
@echo "## Walker regression tests"
-@(for i in $(srcdir)/test/* ; do \
name=`basename $$i`; \
if [ ! -d $$i ] ; then \
if [ ! -f $(srcdir)/result/$$name.rdr ] ; then \
echo New test file $$name ; \
$(CHECKER) $(top_builddir)/xmllint --nonet --debug --walker $$i > $(srcdir)/result/$$name.rdr 2>/dev/null ; \
grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0";\
else \
log=`$(CHECKER) $(top_builddir)/xmllint --nonet --debug --walker $$i > result.$$name 2>/dev/null ; \
grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0";\
diff $(srcdir)/result/$$name.rdr result.$$name` ; \
if [ -n "$$log" ] ; then echo $$name result ; echo $$log ; fi ; \
rm result.$$name ; \
fi ; fi ; done)
SAXtests : testSAX$(EXEEXT)
@(echo > .memdump)
@echo "## SAX callbacks regression tests"
......
......@@ -19,11 +19,35 @@
extern "C" {
#endif
#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
#define XINCLUDE_NODE (const xmlChar *) "include"
#define XINCLUDE_FALLBACK (const xmlChar *) "fallback"
#define XINCLUDE_HREF (const xmlChar *) "href"
#define XINCLUDE_PARSE (const xmlChar *) "parse"
#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
#define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding"
typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
/*
* standalone processing
*/
XMLPUBFUN int XMLCALL
xmlXIncludeProcess (xmlDocPtr doc);
xmlXIncludeProcess (xmlDocPtr doc);
XMLPUBFUN int XMLCALL
xmlXIncludeProcessTree (xmlNodePtr tree);
xmlXIncludeProcessTree (xmlNodePtr tree);
/*
* contextual processing
*/
XMLPUBFUN xmlXIncludeCtxtPtr XMLCALL
xmlXIncludeNewContext (xmlDocPtr doc);
XMLPUBFUN void XMLCALL
xmlXIncludeFreeContext (xmlXIncludeCtxtPtr ctxt);
XMLPUBFUN int XMLCALL
xmlXIncludeProcessNode (xmlXIncludeCtxtPtr ctxt,
xmlNodePtr tree);
#ifdef __cplusplus
}
#endif
......
0 10 book 0 0
0 1 book 0 0
1 14 #text 0 1
1 1 doc 0 0
2 14 #text 0 1
2 1 isid 1 0
2 14 #text 0 1
2 1 isid 1 0
2 14 #text 0 1
1 15 doc 0 0
1 14 #text 0 1
1 8 #comment 0 1 including another XML document with IDs
1 14 #text 0 1
1 1 doc 0 0
2 14 #text 0 1
2 1 isid 1 0
2 14 #text 0 1
2 1 isid 1 0
2 14 #text 0 1
2 1 isid 1 0
2 14 #text 0 1
1 15 doc 0 0
1 14 #text 0 1
0 15 book 0 0
0 1 x 0 0
1 14 #text 0 1
1 8 #comment 0 1 Simple test of a fallback on unavailble URI
1 14 #text 0 1
1 1 warning 0 0
2 3 #text 0 1 Inclusion failed
1 15 warning 0 0
1 14 #text 0 1
0 15 x 0 0
0 1 x 0 0
1 14 #text 0 1
1 8 #comment 0 1 Simple test of including another XML document
1 14 #text 0 1
1 1 doc 0 0
2 14 #text 0 1
2 1 p 0 0
3 3 #text 0 1 something
2 15 p 0 0
2 14 #text 0 1
2 1 p 0 0
3 3 #text 0 1 really
2 15 p 0 0
2 14 #text 0 1
2 1 p 0 0
3 3 #text 0 1 simple
2 15 p 0 0
2 14 #text 0 1
1 15 doc 0 0
1 14 #text 0 1
0 15 x 0 0
0 1 x 0 0
1 14 #text 0 1
1 8 #comment 0 1 Simple test of including a set of nodes from an XML document
1 14 #text 0 1
1 1 p 0 0
2 3 #text 0 1 something
1 15 p 0 0
1 1 p 0 0
2 3 #text 0 1 really
1 15 p 0 0
1 1 p 0 0
2 3 #text 0 1 simple
1 15 p 0 0
1 14 #text 0 1
0 15 x 0 0
0 1 this 0 0
1 1 sub-inc 0 0
2 3 #text 0 1 is a test
1 15 sub-inc 0 0
0 15 this 0 0
0 1 x 0 0
1 14 #text 0 1
1 8 #comment 0 1 Simple test of including another text document
1 14 #text 0 1
1 3 #text 0 1 test with accents in ISO-8859-1: À Á é è
1 14 #text 0 1
0 15 x 0 0
0 1 x 0 0
1 14 #text 0 1
1 8 #comment 0 1 Simple test of including another text document
1 14 #text 0 1
1 3 #text 0 1 this is some text in ASCII
1 14 #text 0 1
0 15 x 0 0
0 10 doc 0 0
0 1 doc 0 0
0 15 doc 0 0
0 1 doc 1 0
0 10 doc 0 0
0 1 doc 0 0
0 15 doc 0 0
0 1 doc 1 0
......@@ -2,4 +2,4 @@
<!ELEMENT doc (#PCDATA)>
<!ATTLIST doc val CDATA #IMPLIED>
]>
<doc val="v1"></doc>
<doc val="v1"/>
......@@ -5,4 +5,4 @@
<!ENTITY apos "&#39;">
<!ENTITY quot "&#34;">
]>
<doc></doc>
<doc/>
......@@ -26,14 +26,6 @@
#ifdef LIBXML_XINCLUDE_ENABLED
#include <libxml/xinclude.h>
#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
#define XINCLUDE_NODE (const xmlChar *) "include"
#define XINCLUDE_FALLBACK (const xmlChar *) "fallback"
#define XINCLUDE_HREF (const xmlChar *) "href"
#define XINCLUDE_PARSE (const xmlChar *) "parse"
#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
#define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding"
#define XINCLUDE_MAX_DEPTH 40
......@@ -68,8 +60,6 @@ struct _xmlXIncludeRef {
xmlXPathObjectPtr xptr; /* the xpointer if needed */
};
typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
struct _xmlXIncludeCtxt {
xmlDocPtr doc; /* the source document */
int incBase; /* the first include for this document */
......@@ -232,7 +222,7 @@ xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
*
* Returns the new set
*/
static xmlXIncludeCtxtPtr
xmlXIncludeCtxtPtr
xmlXIncludeNewContext(xmlDocPtr doc) {
xmlXIncludeCtxtPtr ret;
......@@ -330,7 +320,7 @@ xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
*
* Free an XInclude context
*/
static void
void
xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
int i;
......@@ -2118,5 +2108,28 @@ xmlXIncludeProcessTree(xmlNodePtr tree) {
return(ret);
}
/**
* xmlXIncludeProcessNode:
* @ctxt: an existing XInclude context
* @node: a node in an XML document
*
* Implement the XInclude substitution for the given subtree reusing
* the informations and data coming from the given context.
*
* Returns 0 if no substitution were done, -1 if some processing failed
* or the number of substitutions done.
*/
int
xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
int ret = 0;
if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
return(-1);
ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
if ((ret >= 0) && (ctxt->nbErrors > 0))
ret = -1;
return(ret);
}
#else /* !LIBXML_XINCLUDE_ENABLED */
#endif
......@@ -153,6 +153,7 @@ static int nocatalogs = 0;
#endif
#ifdef LIBXML_READER_ENABLED
static int stream = 0;
static int walker = 0;
#endif /* LIBXML_READER_ENABLED */
static int chkregister = 0;
#ifdef LIBXML_SAX1_ENABLED
......@@ -603,7 +604,7 @@ static void processNode(xmlTextReaderPtr reader) {
name = xmlTextReaderConstName(reader);
if (name == NULL)
name = xmlStrdup(BAD_CAST "--");
name = BAD_CAST "--";
value = xmlTextReaderConstValue(reader);
......@@ -638,12 +639,12 @@ static void streamFile(char *filename) {
if (base == (void *) MAP_FAILED)
return;
input = xmlParserInputBufferCreateStatic((char *) base, info.st_size,
XML_CHAR_ENCODING_NONE);
reader = xmlNewTextReader(input, filename);
reader = xmlReaderForMemory(base, info.st_size, filename,
NULL, options);
} else
#endif
reader = xmlNewTextReaderFilename(filename);
reader = xmlReaderForFile(filename, NULL, options);
if (reader != NULL) {
#ifdef LIBXML_VALID_ENABLED
......@@ -734,6 +735,35 @@ static void streamFile(char *filename) {
}
#endif
}
static void walkDoc(xmlDocPtr doc) {
xmlTextReaderPtr reader;
int ret;
reader = xmlReaderWalker(doc);
if (reader != NULL) {
if ((timing) && (!repeat)) {
startTimer();
}
ret = xmlTextReaderRead(reader);
while (ret == 1) {
if (debug)
processNode(reader);
ret = xmlTextReaderRead(reader);
}
if ((timing) && (!repeat)) {
endTimer("walking through the doc");
}
xmlFreeTextReader(reader);
if (ret != 0) {
printf("failed to walk through the doc\n");
progresult = 1;
}
} else {
fprintf(stderr, "Failed to crate a reader from the document\n");
progresult = 1;
}
}
#endif /* LIBXML_READER_ENABLED */
/************************************************************************
......@@ -1006,6 +1036,11 @@ static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) {
}
}else
#endif /* LIBXML_VALID_ENABLED */
#ifdef LIBXML_READER_ENABLED
if (walker) {
walkDoc(doc);
}
#endif /* LIBXML_READER_ENABLED */
#ifdef LIBXML_OUTPUT_ENABLED
if (noout == 0) {
/*
......@@ -1386,6 +1421,7 @@ static void usage(const char *name) {
printf("\t--dtdattr : loaddtd + populate the tree with inherited attributes \n");
#ifdef LIBXML_READER_ENABLED
printf("\t--stream : use the streaming interface to process very large files\n");
printf("\t--walker : create a reader and walk though the resulting doc\n");
#endif /* LIBXML_READER_ENABLED */
printf("\t--chkregister : verify the node registration code\n");
#ifdef LIBXML_SCHEMAS_ENABLED
......@@ -1553,7 +1589,7 @@ main(int argc, char **argv) {
else if ((!strcmp(argv[i], "-xinclude")) ||
(!strcmp(argv[i], "--xinclude"))) {
xinclude++;
/* options |= XML_PARSE_XINCLUDE; */
options |= XML_PARSE_XINCLUDE;
}
#endif
#ifdef LIBXML_OUTPUT_ENABLED
......@@ -1620,6 +1656,11 @@ main(int argc, char **argv) {
(!strcmp(argv[i], "--stream"))) {
stream++;
}
else if ((!strcmp(argv[i], "-walker")) ||
(!strcmp(argv[i], "--walker"))) {
walker++;
noout++;
}
#endif /* LIBXML_READER_ENABLED */
#ifdef LIBXML_SAX1_ENABLED
else if ((!strcmp(argv[i], "-sax1")) ||
......
......@@ -38,6 +38,9 @@
#include <libxml/parserInternals.h>
#include <libxml/relaxng.h>
#include <libxml/uri.h>
#ifdef LIBXML_XINCLUDE_ENABLED
#include <libxml/xinclude.h>
#endif
/* #define DEBUG_CALLBACKS */
/* #define DEBUG_READER */
......@@ -132,10 +135,17 @@ struct _xmlTextReader {
#ifdef LIBXML_SCHEMAS_ENABLED
/* Handling of RelaxNG validation */
xmlRelaxNGPtr rngSchemas; /* The Relax NG schemas */
xmlRelaxNGValidCtxtPtr rngValidCtxt; /* The Relax NG validation context */
int rngValidErrors; /* The number of errors detected */
xmlNodePtr rngFullNode; /* the node if RNG not progressive */
xmlRelaxNGPtr rngSchemas; /* The Relax NG schemas */
xmlRelaxNGValidCtxtPtr rngValidCtxt;/* The Relax NG validation context */
int rngValidErrors;/* The number of errors detected */
xmlNodePtr rngFullNode; /* the node if RNG not progressive */
#endif
#ifdef LIBXML_XINCLUDE_ENABLED
/* Handling of XInclude processing */
int xinclude; /* is xinclude asked for */
const xmlChar * xinclude_name; /* the xinclude name from dict */
xmlXIncludeCtxtPtr xincctxt; /* the xinclude context */
int in_xinclude; /* counts for xinclude */
#endif
};
......@@ -1155,6 +1165,7 @@ get_next_node:
if (oldstate != XML_TEXTREADER_BACKTRACK) {
if ((reader->node->children != NULL) &&
(reader->node->type != XML_ENTITY_REF_NODE) &&
(reader->node->type != XML_XINCLUDE_START) &&
(reader->node->type != XML_DTD_NODE)) {
reader->node = reader->node->children;
reader->depth++;
......@@ -1166,7 +1177,8 @@ get_next_node:
if ((oldstate == XML_TEXTREADER_ELEMENT) &&
(reader->node->type == XML_ELEMENT_NODE) &&
(reader->node->children == NULL) &&
((reader->node->extra & NODE_IS_EMPTY) == 0)) {
((reader->node->extra & NODE_IS_EMPTY) == 0) &&
(reader->in_xinclude <= 0)) {
reader->state = XML_TEXTREADER_END;
goto node_found;
}
......@@ -1246,6 +1258,32 @@ node_found:
xmlTextReaderExpand(reader);
}
#ifdef LIBXML_XINCLUDE_ENABLED
/*
* Handle XInclude if asked for
*/
if ((reader->xinclude) && (reader->node != NULL) &&
(reader->node->type == XML_ELEMENT_NODE) &&
(reader->node->ns != NULL) &&
(xmlStrEqual(reader->node->ns->href, XINCLUDE_NS))) {
if (reader->xincctxt == NULL) {
reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc);
}
/*
* expand that node and process it
*/
xmlTextReaderExpand(reader);
xmlXIncludeProcessNode(reader->xincctxt, reader->node);
}
if (reader->node->type == XML_XINCLUDE_START) {
reader->in_xinclude++;
goto get_next_node;
}
if (reader->node->type == XML_XINCLUDE_END) {
reader->in_xinclude--;
goto get_next_node;
}
#endif
/*
* Handle entities enter and exit when in entity replacement mode
*/
......@@ -1491,14 +1529,14 @@ xmlTextReaderReadBinHex(xmlTextReaderPtr reader,
static int
xmlTextReaderNextTree(xmlTextReaderPtr reader)
{
if (reader == 0)
if (reader == NULL)
return(-1);
if (reader->state == XML_TEXTREADER_END)
return(0);
if (reader->node == 0) {
if (reader->doc->children == 0) {
if (reader->node == NULL) {
if (reader->doc->children == NULL) {
reader->state = XML_TEXTREADER_END;
return(0);
}
......@@ -1561,6 +1599,7 @@ xmlTextReaderReadTree(xmlTextReaderPtr reader) {
if (reader->state == XML_TEXTREADER_END)
return(0);
next_node:
if (reader->node == NULL) {
if (reader->doc->children == NULL) {
reader->state = XML_TEXTREADER_END;
......@@ -1569,31 +1608,33 @@ xmlTextReaderReadTree(xmlTextReaderPtr reader) {
reader->node = reader->doc->children;
reader->state = XML_TEXTREADER_START;
return(1);
goto found_node;
}
if (reader->state != XML_TEXTREADER_BACKTRACK) {
if (reader->node->children != 0) {
if ((reader->state != XML_TEXTREADER_BACKTRACK) &&
(reader->node->type != XML_DTD_NODE) &&
(reader->node->type != XML_XINCLUDE_START) &&
(reader->node->type != XML_ENTITY_REF_NODE)) {
if (reader->node->children != NULL) {
reader->node = reader->node->children;
reader->depth++;
reader->state = XML_TEXTREADER_START;
return(1);
goto found_node;
}
if ((reader->node->type == XML_ELEMENT_NODE) ||
(reader->node->type == XML_ATTRIBUTE_NODE)) {
if (reader->node->type == XML_ATTRIBUTE_NODE) {
reader->state = XML_TEXTREADER_BACKTRACK;
return(1);
goto found_node;
}
}
if (reader->node->next != 0) {
if (reader->node->next != NULL) {
reader->node = reader->node->next;
reader->state = XML_TEXTREADER_START;
return(1);
goto found_node;
}
if (reader->node->parent != 0) {
if (reader->node->parent != NULL) {
if ((reader->node->parent->type == XML_DOCUMENT_NODE) ||
(reader->node->parent->type == XML_HTML_DOCUMENT_NODE)) {
reader->state = XML_TEXTREADER_END;
......@@ -1603,11 +1644,16 @@ xmlTextReaderReadTree(xmlTextReaderPtr reader) {
reader->node = reader->node->parent;
reader->depth--;
reader->state = XML_TEXTREADER_BACKTRACK;
return(1);
goto found_node;
}
reader->state = XML_TEXTREADER_END;
found_node:
if ((reader->node->type == XML_XINCLUDE_START) ||
(reader->node->type == XML_XINCLUDE_END))
goto next_node;
return(1);
}
......@@ -1634,10 +1680,10 @@ xmlTextReaderNextSibling(xmlTextReaderPtr reader) {
if (reader->state == XML_TEXTREADER_END)
return(0);
if (reader->node == 0)
if (reader->node == NULL)
return(xmlTextReaderNextTree(reader));
if (reader->node->next != 0) {
if (reader->node->next != NULL) {
reader->node = reader->node->next;
reader->state = XML_TEXTREADER_START;
return(1);
......@@ -1742,6 +1788,9 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
*/
ret->ctxt->docdict = 1;
ret->dict = ret->ctxt->dict;
#ifdef LIBXML_XINCLUDE_ENABLED
ret->xinclude = 0;
#endif
return(ret);
}
......@@ -1796,6 +1845,10 @@ xmlFreeTextReader(xmlTextReaderPtr reader) {
xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
reader->rngValidCtxt = NULL;
}
#endif
#ifdef LIBXML_XINCLUDE_ENABLED
if (reader->xincctxt != NULL)
xmlXIncludeFreeContext(reader->xincctxt);
#endif
if (reader->ctxt != NULL) {
if (reader->dict == reader->ctxt->dict)
......@@ -2552,6 +2605,10 @@ xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
return(0);
if (reader->state == XML_TEXTREADER_END)
return(0);
if (reader->doc != NULL)
return(1);
if (reader->in_xinclude > 0)
return(1);
return((reader->node->extra & NODE_IS_EMPTY) != 0);
}
......@@ -3916,6 +3973,19 @@ xmlTextReaderSetup(xmlTextReaderPtr reader,
*/
reader->ctxt->docdict = 1;
#ifdef LIBXML_XINCLUDE_ENABLED
if (reader->xincctxt != NULL) {
xmlXIncludeFreeContext(reader->xincctxt);
reader->xincctxt = NULL;
}
if (options & XML_PARSE_XINCLUDE) {
reader->xinclude = 1;
reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1);
options -= XML_PARSE_XINCLUDE;
} else
reader->xinclude = 0;
reader->in_xinclude = 0;