Rev 7747 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/*This file uses the HTML parser in libxml to provide an HTMLparser in R that is basically identical to the XML parsing interface.It can handle files, URLs, compressed files, and raw HTML text.It drops the DTD and validation options since these are not very relevantfor HTML. (We can add put them back if anyone wants!)*/#include "DocParse.h"#include "Utils.h"#include "libxml/HTMLparser.h"#include "libxml/HTMLtree.h"#include <sys/stat.h>#include <unistd.h>USER_OBJECT_RS_XML(HtmlParseTree)(USER_OBJECT_ fileName, USER_OBJECT_ converterFunctions,USER_OBJECT_ skipBlankLines, USER_OBJECT_ replaceEntities,USER_OBJECT_ asText, USER_OBJECT_ trim, USER_OBJECT_ isURL){const char *name;xmlDocPtr doc;USER_OBJECT_ rdoc;USER_OBJECT_ className;R_XMLSettings parserSettings;int freeName = 0;int asTextBuffer = LOGICAL_DATA(asText)[0];int isURLDoc = LOGICAL_DATA(isURL)[0];parserSettings.skipBlankLines = LOGICAL_DATA(skipBlankLines)[0];parserSettings.converters = converterFunctions;parserSettings.trim = LOGICAL_DATA(trim)[0];if(asTextBuffer == 0) {struct stat tmp_stat;#ifdef USE_Rname = CHAR(STRING_ELT(fileName, 0));#elsename = CHARACTER_DATA(fileName)[0];#endifif(!isURLDoc && (name == NULL || stat(name, &tmp_stat) < 0)) {Rf_error("Can't find file %s", CHAR_DEREF(STRING_ELT(fileName, 0)) );}} else {name = strdup(CHAR_DEREF(STRING_ELT(fileName, 0)));freeName = 1;}#if 0/* If one wants entities expanded directly and to appear as text. */if(LOGICAL_DATA(replaceEntities)[0])xmlSubstituteEntitiesDefault(1);#endifif(asTextBuffer) {doc = htmlParseDoc(CHAR_TO_XMLCHAR(name), NULL);if(doc != NULL) {doc->name = (char *) xmlStrdup(CHAR_TO_XMLCHAR("<buffer>"));}} else {doc = htmlParseFile(name, NULL);}if(doc == NULL) {if(freeName && name)free((char *) name);Rf_error("error in creating parser for %s", name);}PROTECT(rdoc = RS_XML(convertXMLDoc)(name, doc, converterFunctions, &parserSettings));if(freeName && name)free((char *) name);#if 0xmlFreeDoc(doc);R_numXMLDocsFreed++;#endif/* Set the class for the document. */className = NEW_CHARACTER(1);PROTECT(className);SET_STRING_ELT(className, 0, mkChar("HTMLDocument"));SET_CLASS(rdoc, className);UNPROTECT(1);UNPROTECT(1);return(rdoc);}/*Copied from RS_XML_printXMLNode (XMLTree.c) with minor changes.*/USER_OBJECT_RS_XML_dumpHTMLDoc(USER_OBJECT_ r_node, USER_OBJECT_ format, USER_OBJECT_ r_encoding, USER_OBJECT_ indent, USER_OBJECT_ outFile){USER_OBJECT_ ans;xmlDocPtr node;const char *encoding = NULL;xmlOutputBufferPtr buf;xmlBufferPtr xbuf;int oldIndent;oldIndent = xmlIndentTreeOutput;node = (xmlDocPtr) R_ExternalPtrAddr(r_node);xmlIndentTreeOutput = LOGICAL(indent)[0];#if ADD_XML_OUTPUT_BUFFER_CODEif(Rf_length(outFile)) {htmlSaveFile(CHAR_DEREF(STRING_ELT(outFile, 0)), node);return(R_NilValue);}#endifif(GET_LENGTH(r_encoding))encoding = CHAR_DEREF(STRING_ELT(r_encoding, 0));xbuf = xmlBufferCreate();#if 1buf = xmlOutputBufferCreateBuffer(xbuf, NULL);#elsebuf = xmlOutputBufferCreateFilename("/tmp/test.out", NULL, 0);#endifhtmlDocContentDumpFormatOutput(buf, node, encoding, INTEGER(format)[0]);xmlOutputBufferFlush(buf);xmlIndentTreeOutput = oldIndent;if(xbuf->use > 0) {/*XXX this const char * in CHARSXP means we have to make multiple copies. */#if 0char *rbuf = R_alloc(sizeof(char) * (xbuf->use + 1));memcpy(rbuf, xbuf->content, xbuf->use + 1);PROTECT(tmp = mkChar(rbuf));#endif// ans = ScalarString(mkChar(xbuf->content));DECL_ENCODING_FROM_DOC(node)ans = ScalarString(ENC_COPY_TO_USER_STRING(XMLCHAR_TO_CHAR(xbuf->content)));} elseans = NEW_CHARACTER(1);xmlOutputBufferClose(buf);return(ans);}