
Contents of /Public_Parser_XML2-1.42/XML2.cmod:
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: XML2.cmod,v 1.106 2008-02-01 19:55:58 hww3 Exp $
*/
/*
* File licensing and authorship information block.
*
* Version: MPL 1.1/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Initial Developer of the Original Code is
*
* Bill Welliver <hww3@riverweb.com>
*
* Portions created by the Initial Developer are Copyright (C) Bill Welliver
* All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of the LGPL, and not to allow others to use your version
* of this file under the terms of the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL or the LGPL.
*
* Significant Contributors to this file are:
*
*
*/
#include "xml2.h"
/*! @module Public
*/
/*! @module Parser
*/
/*! @module XML2
*/
/*
start of Public.Parser.XML2 module functions
*/
static void
xmlDetectSAX2(xmlParserCtxtPtr ctxt) {
if (ctxt == NULL) return;
#ifdef LIBXML_SAX1_ENABLED
if ((ctxt->sax) && (ctxt->sax->initialized == XML_SAX2_MAGIC) &&
((ctxt->sax->startElementNs != NULL) ||
(ctxt->sax->endElementNs != NULL))) ctxt->sax2 = 1;
#else
ctxt->sax2 = 1;
#endif /* LIBXML_SAX1_ENABLED */
ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3);
ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5);
ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36);
if ((ctxt->str_xml==NULL) || (ctxt->str_xmlns==NULL) ||
(ctxt->str_xml_ns == NULL)) {
xmlErrMemory(ctxt, NULL);
}
}
CVAR PARSER_OBJECT_DATA * object_data;
PIKEVAR int silent;
PIKEFUN void create()
{
}
/*! @decl array(Node) select_xpath_nodes(string xpath, object node)
*!
*! selects nodes based on an XPath query and returns the result.
*/
PIKEFUN array select_xpath_nodes(string xpath, object node)
{
xmlXPathContextPtr xpathCtx;
xmlXPathObjectPtr xpathObj;
xmlNodeSetPtr set;
xmlNodePtr xn;
xmlNsPtr xmlns;
struct object * o;
int num_nodes = 0;
CHECK_NODE_PASSED(node);
if(OBJ2_NODE(node)->object_data->node == NULL)
{
pop_n_elems(2);
Pike_error("Node not initialized.\n");
}
xpathCtx = xmlXPathNewContext(OBJ2_NODE(node)->object_data->node->doc);
if(xpathCtx == NULL)
{
pop_n_elems(2);
Pike_error("Unable to create new XPath context.\n");
}
/*
xmlns = xmlGetNsList(OBJ2_NODE(node)->object_data->node->doc,
OBJ2_NODE(node)->object_data->node);
while(xmlns != NULL)
{
printf("registering ns %s, %s\n", xmlns->prefix, xmlns->href);
xmlXPathRegisterNs(xpathCtx, xmlns->prefix, xmlns->href);
xmlns = xmlns->next;
}
*/
xpathCtx->node = OBJ2_NODE(node)->object_data->node;
xpathObj = xmlXPathEvalExpression((xmlChar *)xpath->str, xpathCtx);
if(xpathObj == NULL) {
pop_n_elems(2);
xmlXPathFreeContext(xpathCtx);
Pike_error("Unable to evaluate the XPath expression.\n");
}
/* now we should generate an array from the node set. */
set = xpathObj->nodesetval;
if(set == NULL)
{
pop_n_elems(2);
push_int(0);
xmlXPathFreeContext(xpathCtx);
xmlXPathFreeObject(xpathObj);
return;
}
pop_n_elems(2);
if(set->nodeNr > 0)
{
xn = set->nodeTab[0];
if(xn != NULL && set->nodeNr > 0) do
{
struct Node_struct * ns;
NODE_OBJECT_DATA * od;
apply(Pike_fp->current_object, "Node", 0);
ns = OBJ2_NODE((Pike_sp[0-1].u.object));
od = (NODE_OBJECT_DATA *)(ns->object_data);
od->node=xn;
od->parser = this_object();
od->refs = OBJ2_NODE(node)->object_data->refs;
(* od->refs)++;
num_nodes++;
xn = set->nodeTab[num_nodes];
}
while (((num_nodes +1) <= set->nodeNr) && xn != NULL);
if(num_nodes>0) {
f_aggregate(num_nodes);
}
}
else push_int(0);
xmlXPathFreeContext(xpathCtx);
xmlXPathFreeObject(xpathObj);
return;
}
/*! @decl void set_xml_parser_options(int options)
*!
*! sets parser options.
*!
*! @param options
*! a bitwise or of @[Public.Parser.XML2.Constants] options
*! where valid options start with PARSE_.
*/
PIKEFUN void set_xml_parser_options(int options)
{
THIS->object_data->xml_parser_options = options;
pop_stack();
}
/*! @decl int get_xml_parser_options()
*!
*! gets parser options for XML mode parsing.
*!
*! @returns
*! a bitwise or of @[Public.Parser.XML2.Constants] options
*! where valid options start with PARSE_.
*/
PIKEFUN int get_xml_parser_options()
{
push_int(THIS->object_data->xml_parser_options);
}
/*! @decl int get_html_parser_options()
*!
*! gets parser options for HTML mode parsing.
*!
*! @returns
*! a bitwise or of @[Public.Parser.XML2.Constants] options
*! where valid options start with PARSE_.
*/
PIKEFUN int get_html_parser_options()
{
push_int(THIS->object_data->html_parser_options);
}
/*! @decl void set_auto_utf8_convert(int flag)
*!
*! sets whether the parser should automatically convert input to the parser to and from UTF-8.
*! libxml2 requires input (aside from data to be parsed, which may be encoded differently) to be
*! UTF-8 encoded. This module will automatically convert all string input to and from UTF-8. Calling
*! this function with an argument of zero (0) will turn this feature off. In this case, you will be
*! responsible for ensuring that any input is properly encoded (if necessary).
*!
*! @param flag
*! a boolean value: 0 disables auto conversion, 1 enables.
*/
PIKEFUN void set_auto_utf8_convert(int flag)
{
THIS->object_data->auto_encode = flag;
pop_stack();
}
void f_convert_string_utf8(INT32 args)
{
if( OBJ2_(THIS_NODE->object_data->parser)->object_data->auto_encode !=0)
{
f_string_to_utf8(args);
}
}
void f_convert_utf8_string(INT32 args)
{
if( OBJ2_(THIS_NODE->object_data->parser)->object_data->auto_encode !=0)
{
f_utf8_to_string(args);
}
}
void f_rconvert_string_utf8(INT32 args)
{
if(THIS_XMLREADER->object_data->autoencode !=0)
{
f_string_to_utf8(args);
}
}
void f_rconvert_utf8_string(INT32 args)
{
if( OBJ2_(THIS_XMLREADER->object_data->parser)->object_data->auto_encode !=0)
{
f_utf8_to_string(args);
}
}
/*! @decl void set_html_parser_options(int options)
*!
*! sets parser options.
*!
*! @param options
*! a bitwise or of @[Public.Parser.XML2.Constants] options
*! where valid options start with PARSE_.
*/
PIKEFUN void set_html_parser_options(int options)
{
THIS->object_data->html_parser_options = options;
pop_stack();
}
/*! @decl int substituteEntitiesDefault(int def)
*/
PIKEFUN int substituteEntitiesDefault(int def)
{
def = def ? 1 : 0;
pop_n_elems(args);
xmlSubstituteEntitiesDefault(def);
push_int(def);
}
/* @decl int keepBlanksDefault(int def)
*/
PIKEFUN int keepBlanksDefault(int def)
{
def = def ? 1 : 0;
pop_n_elems(args);
push_int(xmlKeepBlanksDefault(def));
}
/*! @decl string utf8_to_html(string str)
*!
*/
PIKEFUN string utf8_to_html(string str)
{
char *html = NULL;
int outlen, inlen;
outlen = str->len << 1;
html = (char*)malloc(outlen + 1);
if (!html)
Pike_error("Out of memory");
inlen = str->len;
if ( UTF8ToHtml(html, &outlen, str->str, &inlen) < 0 ) {
free(html);
Pike_error("Cannot convert to html!");
}
html[outlen] = '\0';
pop_n_elems(args);
push_text(html);
free(html);
}
/*! @decl string utf8_to_isolat1(string str)
*!
*/
PIKEFUN string utf8_to_isolat1(string str)
{
char *html = NULL;
int outlen, inlen;
outlen = str->len << 1;
html = (char*)malloc(outlen + 1);
if (!html)
Pike_error("Out of memory");
inlen = str->len;
if ( UTF8Toisolat1(html, &outlen, str->str, &inlen) < 0 ) {
free(html);
Pike_error("Cannot convert to isolat1!");
}
html[outlen] = '\0';
pop_n_elems(args);
push_text(html);
free(html);
}
/*! @decl int utf8_check(string str)
*!
*/
PIKEFUN int utf8_check(string str)
{
int result;
result = xmlCheckUTF8(str->str);
pop_n_elems(args);
push_int(result);
}
/*! @decl array(int) get_encodings()
*!
*! gets the list of available character encoders.
*!
*! @returns
*! an array of available encoder identifiers.
*!
*/
PIKEFUN array get_encodings()
{
int num = 0;
int cur = 0;
int upper_limit = 25;
xmlCharEncodingHandlerPtr encoder;
for (cur = 0; cur < upper_limit; cur++)
{
encoder = xmlGetCharEncodingHandler((xmlCharEncoding)cur);
if(encoder != NULL)
{
push_int(cur);
num++;
xmlFree(encoder);
}
}
f_aggregate(num);
return;
}
/*! @decl string get_encoding_name(int e)
*!
*/
PIKEFUN string get_encoding_name(int e)
{
const char * enc = NULL;
enc = xmlGetCharEncodingName(e);
if(enc != NULL)
push_text(enc);
else
push_int(0);
}
/*! @decl string get_encoding_alias(string e)
*!
*/
PIKEFUN string get_encoding_alias(string e)
{
const char * enc = NULL;
enc = xmlGetEncodingAlias(e->str);
if(enc != NULL)
push_text(enc);
else
push_int(0);
}
/*! @decl string render_xml(Node n)
*! Renders a node tree as an XML string. The entire document tree will
*! be rendered. To render a portion of a tree, use @[Node.render_xml].
*!
*! @param n
*! a Node object for a given XML document.
*!
*/
PIKEFUN string render_xml(object n)
{
int dumped;
xmlChar * buf;
char * str;
int bufsize;
CHECK_NODE_PASSED(n);
// check_node_created();
if(OBJ2_NODE(n)->object_data->node == NULL)
{
Pike_error("Node not initialized.\n");
}
xmlDocDumpFormatMemory(OBJ2_NODE(n)->object_data->node->doc, &buf, &bufsize, 1);
if(buf!=NULL)
{
str = (char *)xmlStrdup(buf);
xmlFree(buf);
push_text(str);
}
else
{
push_int(0);
}
}
/*! @decl string render_html(Node n)
*! Renders a node tree as an HTML string. The entire document tree will
*! be rendered. To render a portion of a tree, use @[Node.render_html].
*!
*! @param n
*! a Node object for a given HTML document.
*!
*/
PIKEFUN string render_html(object n)
{
int dumped;
xmlChar * buf;
char * str;
int bufsize;
CHECK_NODE_PASSED(n);
// check_node_created();
if(OBJ2_NODE(n)->object_data->node == NULL)
{
Pike_error("Node not initialized.\n");
}
htmlDocDumpMemory(OBJ2_NODE(n)->object_data->node->doc, &buf, &bufsize, 1);
if(buf!=NULL)
{
str = (char *)xmlStrdup(buf);
xmlFree(buf);
push_text(str);
}
else
{
push_int(0);
}
}
void my_relaxng_generic_error(void * userData, const char * error)
{
printf("%s\n", error);
// push_text(error);
// f_werror(1);
}
void my_structured_error(void * userData, xmlErrorPtr error)
{
char err[255];
if(THIS->silent == 0)
{
snprintf(err, sizeof(err), "Public.Parser.XML error: %d, message: %s",
error->level, error->message);
// push_text(err);
// f_werror(1);
printf("%s\n", err);
}
}
/*! @decl Node parse_xml_force(string xml)
*! Parse an string containing XML, even if it is not Well Formed.
*! @param xml
*! String containing XML data to parse.
*!
*! @returns
*! a @[Node] object containing the root of the tree.
*/
PIKEFUN object parse_xml_force(string xml)
{
xmlDocPtr doc;
xmlNodePtr node;
struct Node_struct * ns;
NODE_OBJECT_DATA * od;
doc = xmlRecoverMemory(xml->str, xml->len);
if(doc == NULL)
{
pop_n_elems(2);
Pike_error("Unable to parse XML.\n");
}
node = xmlDocGetRootElement(doc);
if(node == NULL)
{
pop_n_elems(2);
xmlFreeDoc(doc);
Pike_error("Unable to find Root Node.\n");
}
// ok, we have a parsed file. now let's turn it into a real live pike object.
pop_n_elems(2);
apply(Pike_fp->current_object, "Node", 0);
ns = OBJ2_NODE((Pike_sp[0-1].u.object));
od = (NODE_OBJECT_DATA *)(ns->object_data);
od->parser = this_object();
od->refs = malloc(sizeof(INT32));
(* od->refs)=1;
od->node = node;
}
xmlParserInputPtr my_entity_loader(const char * URL, const char * ID,
xmlParserCtxtPtr context)
{
printf("request for entity %s\n", URL);
return NULL;
}
/*! @decl Node parse_xml(string xml, string|void name, string|void encoding)
*! Parse an string containing XML.
*! @param xml
*! String containing XML data to parse.
*! @param name
*! String containing name/URI of file.
*!
*! @returns
*! a @[Node] object containing the root of the tree.
*/
PIKEFUN object parse_xml(string xml, string name, string encoding)
{
xmlDocPtr doc;
entity_loader = my_entity_loader;
// xmlSetExternalEntityLoader(entity_loader);
doc = xmlReadMemory(xml->str, xml->len, name->str,
(const char *)encoding->str,
THIS->object_data->xml_parser_options);
handle_parsed_tree(doc, args);
}
xmlEntityPtr my_xml_getent(void * ctx, const xmlChar * name)
{
xmlEntityPtr ent;
if(strcmp(name, "boo") != 0)
{
printf("somebody else's entity: %s!\n", name);
return xmlSAX2GetEntity(ctx, name);
}
ent = xmlMalloc(sizeof(xmlEntity));
if(ent == NULL) printf("unable to allocate entity storage.\n");
memset(ent, 0, sizeof(xmlEntity));
ent->type = XML_ENTITY_DECL;
ent->etype = XML_INTERNAL_GENERAL_ENTITY;
ent->name = xmlStrdup(name);
ent->content = xmlStrdup(name);
return ent;
}
PIKEFUN object parse_xml_sax(string xml, string name, string encoding)
{
xmlDocPtr doc;
xmlSAXHandler * sax;
xmlParserCtxtPtr ctxt;
ctxt = xmlCreateMemoryParserCtxt(xml->str, xml->len);
if(ctxt == NULL) Pike_error("unable to allocate context.\n");
sax = xmlMalloc(sizeof(xmlSAXHandler));
xmlSAXVersion(sax, 2);
sax->getEntity = my_xml_getent;
if(ctxt->sax != NULL)
xmlFree(ctxt->sax);
ctxt->sax = sax;
xmlDetectSAX2(ctxt);
ctxt->recovery = 0;
// ctxt->replaceEntities = 0;
xmlParseDocument(ctxt);
// entity_loader = my_entity_loader;
// xmlSetExternalEntityLoader(entity_loader);
doc = ctxt->myDoc;
if (sax != NULL)
ctxt->sax = NULL;
xmlFreeParserCtxt(ctxt);
handle_parsed_tree(doc, args);
}
void handle_parsed_tree(xmlDocPtr doc, INT32 args)
{
xmlNodePtr node;
struct Node_struct * ns;
NODE_OBJECT_DATA * od;
char * err_ctx = "parse_xml";
if(doc == NULL)
{
pop_n_elems(args);
Pike_error("Unable to parse XML.\n");
}
node = xmlDocGetRootElement(doc);
if(node == NULL)
{
pop_n_elems(args);
xmlFreeDoc(doc);
Pike_error("Unable to find Root Node.\n");
}
// ok, we have a parsed file. now let's turn it into a real live pike object.
pop_n_elems(args);
apply(Pike_fp->current_object, "Node", 0);
ns = OBJ2_NODE((Pike_sp[0-1].u.object));
od = (NODE_OBJECT_DATA *)(ns->object_data);
od->refs = malloc(sizeof(INT32));
(* od->refs)=1;
od->node = node;
od->parser = this_object();
}
PIKEFUN object parse_xml(string xml, string name)
{
xmlDocPtr doc;
entity_loader = my_entity_loader;
// xmlSetExternalEntityLoader(entity_loader);
if(!xml || !name || !THIS || !THIS->object_data)
{
Pike_error("missing arguments at c level!\n");
}
doc = xmlReadMemory(xml->str, xml->len, name->str,
NULL,
THIS->object_data->xml_parser_options);
handle_parsed_tree(doc, args);
}
PIKEFUN object parse_xml(string xml)
{
push_text("noname.xml");
f_parse_xml(2);
}
/*! @decl Node parse_html(string html, string|void name, string|void encoding)
*! Parse an string containing HTML.
*! @param html
*! String containing HTML data to parse.
*! @param name
*! String containing name/URI of file.
*!
*! @returns
*! a @[Node] object containing the root of the tree.
*/
PIKEFUN object parse_html(string html, string name, string encoding)
{
xmlDocPtr doc;
entity_loader = my_entity_loader;
// xmlSetExternalEntityLoader(entity_loader);
doc = htmlReadMemory(html->str, html->len, name->str,
(const char *)encoding->str,
THIS->object_data->html_parser_options);
handle_parsed_tree(doc, args);
}
PIKEFUN object parse_html(string html, string name)
{
xmlDocPtr doc;
entity_loader = my_entity_loader;
// xmlSetExternalEntityLoader(entity_loader);
doc = htmlReadMemory(html->str, html->len, name->str,
NULL,
THIS->object_data->html_parser_options);
handle_parsed_tree(doc, args);
}
PIKEFUN object parse_html(string html)
{
push_text("noname.html");
f_parse_html(2);
}
/*! @decl int validate(Node doc)
*!
*! validates a document against its internal and external DTDs.
*!
*/
PIKEFUN int validate(object doc)
{
int r;
xmlValidCtxtPtr valid;
CHECK_NODE_PASSED(doc);
if(OBJ2_NODE(doc)->object_data->node->doc==NULL)
{
pop_stack();
Pike_error("whoa, horsie! we don't have an xml document!\n");
}
valid = xmlNewValidCtxt();
if(valid == NULL)
{
pop_stack();
Pike_error("unable to allocate a validation context\n");
}
r = xmlValidateDocument(valid, OBJ2_NODE(doc)->object_data->node->doc);
xmlFreeValidCtxt(valid);
pop_stack();
push_int(r);
}
/*! @decl Node new_xml(string version, string root_name)
*! Create a new XML document with a root node.
*!
*! @param version
*! the version of XML to create
*! @param root_name
*! the name of the root node
*! @returns
*! a @[Node] object containing the root of the tree.
*/
PIKEFUN object new_xml(string version, string root_name)
{
xmlDocPtr doc;
xmlNodePtr node;
struct Node_struct * ns;
NODE_OBJECT_DATA * od;
// TODO: we need to encode this value!
doc = xmlNewDoc(version->str);
if(doc == NULL)
{
Pike_error("Unable to create new XML document.\n");
}
// TODO: we need to encode this value!
node = xmlNewNode(NULL, (xmlChar *)root_name->str);
xmlDocSetRootElement(doc, node);
if(node == NULL)
{
xmlFreeDoc(doc);
Pike_error("Unable to find Root Node.\n");
}
// ok, we have a parsed file. now let's turn it into a real live pike object.
pop_stack();
apply(Pike_fp->current_object, "Node", 0);
ns = OBJ2_NODE((Pike_sp[0-1].u.object));
od = (NODE_OBJECT_DATA *)(ns->object_data);
od->refs = malloc(sizeof(INT32));
(* od->refs)=1;
od->node = node;
od->parser = this_object();
}
/*! @decl Node new_node(string name)
*! Create a new unlinked XML node.
*!
*! @param name
*! the node name
*! @returns
*! a new @[Node] object.
*/
PIKEFUN object new_node(string name)
{
xmlNodePtr node;
struct Node_struct * ns;
NODE_OBJECT_DATA * od;
// TODO: we need to encode this value!
node = xmlNewNode(NULL, (xmlChar *)name->str);
if(node == NULL)
{
Pike_error("Unable to create new node.\n");
}
pop_stack();
apply(Pike_fp->current_object, "Node", 0);
ns = OBJ2_NODE((Pike_sp[0-1].u.object));
od = (NODE_OBJECT_DATA *)(ns->object_data);
od->refs = malloc(sizeof(INT32));
(* od->refs)=1;
od->unlinked = 1;
od->node = node;
od->parser = this_object();
}
/*! @decl Node parse_relaxng(string relaxng, string|void name)
/*! @decl Node parse_relaxng(Node relaxng)
*! Parse a string containing an RelaxNG schema.
*!
*! @param name
*! String containing name/URI of file.
*!
*! @returns
*! a @[RelaxNG] object containing the parsed schema.
*/
PIKEFUN object parse_relaxng(string relaxng)
{
push_text("noname.rlx");
f_parse_relaxng(2);
}
PIKEFUN object parse_relaxng(object relaxng)
{
CHECK_NODE_PASSED(relaxng);
handle_parse_relaxng(args);
}
PIKEFUN object parse_relaxng(string relaxng, string name)
{
// first, we must parse the xml file. conveniently, we have a function
// that does that already!
f_parse_xml(2);
handle_parse_relaxng(args);
}
void handle_parse_relaxng(INT32 args)
{
struct object * node_obj = NULL;
xmlDocPtr doc = NULL;
xmlRelaxNGParserCtxtPtr parser;
xmlRelaxNGPtr relax;
struct RelaxNG_struct * rn;
RELAXNG_OBJECT_DATA * od;
// we're going to hang on to the node object.
node_obj = Pike_sp[0-1].u.object;
add_ref(node_obj);
doc = OBJ2_NODE(node_obj)->object_data->node->doc;
if(doc==NULL)
{
pop_stack();
Pike_error("whoa, horsie! we don't have an xml document!\n");
}
parser = xmlRelaxNGNewDocParserCtxt(doc);
if(parser == NULL)
{
pop_stack();
Pike_error("Unable to create relaxng parser context.\n");
}
relaxng_error_handler = (xmlRelaxNGValidityErrorFunc)my_relaxng_generic_error;
relaxng_warning_handler = (xmlRelaxNGValidityWarningFunc)my_relaxng_generic_error;
xmlRelaxNGSetParserErrors(parser, relaxng_error_handler,
relaxng_warning_handler, NULL);
relax = xmlRelaxNGParse(parser);
if(relax == NULL)
{
pop_stack();
Pike_error("Unable to parse the relaxng data.\n");
}
// ok, we have a parsed schema. now let's turn it into a real live pike object.
pop_stack();
apply(Pike_fp->current_object, "RelaxNG", 0);
rn = OBJ2_RELAXNG((Pike_sp[0-1].u.object));
od = (RELAXNG_OBJECT_DATA *)(rn->object_data);
od->parser = this_object();
od->refs = malloc(sizeof(INT32));
(* od->refs)=1;
/* TODO: not sure if this is a leak, but we need it to prevent the
xmlNode from being freed a second time at the pike Node's destruction
(the Stylesheet will free that itself. Note that this is a tricky
subject... since the two are linked, perhaps we should call
Node.destroy() when the Stylesheet is destroyed... */
*(OBJ2_NODE(node_obj)->object_data->refs)++;
od->context = parser;
od->valid = relax;
rn->node = node_obj;
}
/*! @decl Node parse_xslt(string xslt, string|void name)
/*! @decl Node parse_xslt(Node xslt)
*! Parse a string containing an XSLT stylesheet.
*!
*! @param name
*! String containing name/URI of file.
*!
*! @returns
*! a @[Stylesheet] object containing the parsed stylesheet.
*/
PIKEFUN object parse_xslt(string xslt)
{
push_text("noname.xsl");
f_parse_xslt(2);
}
PIKEFUN object parse_xslt(object xslt)
{
CHECK_NODE_PASSED(xslt);
handle_parse_stylesheet(args);
}
PIKEFUN object parse_xslt(string xslt, string name)
{
// first, we must parse the xml file. conveniently, we have a function
// that does that already!
f_parse_xml(2);
handle_parse_stylesheet(args);
}
void handle_parse_stylesheet(INT32 args)
{
struct object * node_obj = NULL;
xsltStylesheetPtr sty = NULL;
xmlDocPtr doc = NULL;
struct Stylesheet_struct * ss;
STYLESHEET_OBJECT_DATA * od;
// we're going to hang on to the node object.
node_obj = Pike_sp[0-1].u.object;
add_ref(node_obj);
doc = OBJ2_NODE(node_obj)->object_data->node->doc;
if(doc==NULL)
{
pop_stack();
Pike_error("whoa, horsie! we don't have an xml document!\n");
}
sty = xsltParseStylesheetDoc(doc);
if(sty == NULL)
{
pop_stack();
Pike_error("Unable to parse stylesheet node.\n");
}
// ok, we have a parsed sheet. now let's turn it into a real live pike object.
pop_stack();
apply(Pike_fp->current_object, "Stylesheet", 0);
ss = OBJ2_STYLESHEET((Pike_sp[0-1].u.object));
od = (STYLESHEET_OBJECT_DATA *)(ss->object_data);
od->parser = this_object();
od->refs = malloc(sizeof(INT32));
(* od->refs)=1;
add_ref(node_obj);
// (*(OBJ2_NODE(node_obj)->object_data->refs))++;
od->stylesheet = sty;
ss->node = node_obj;
}
EXTRA
{
struct pike_string * ps;
char * err_ctx = "parse_xml";
add_string_constant("__version", "1.42", 0);
add_string_constant("__author", "Bill Welliver <bill@welliver.org>", 0);
structured_handler = my_structured_error;
xmlSetStructuredErrorFunc((void *)err_ctx, structured_handler);
pike_init_xml2_constants();
pike_init_xml2_html();
pike_init_xml2_node();
pike_init_xml2_sax();
pike_init_xml2_stylesheet();
pike_init_xml2_xmlreader();
pike_init_xml2_relaxng();
}
INIT
{
PARSER_OBJECT_DATA * dta;
dta = (PARSER_OBJECT_DATA*)malloc(sizeof(PARSER_OBJECT_DATA));
if(dta == NULL)
{
Pike_error("xml2_init: unable to allocate memory.\n");
}
dta->xml_parser_options = 0;
dta->html_parser_options = 0;
dta->auto_encode = 1;
if(THIS!=NULL && THIS->object_data != NULL && THIS->object_data != NULL && dta != NULL)
THIS->object_data = dta;
LIBXML_TEST_VERSION
}
EXIT
{
pike_exit_xml2_relaxng();
pike_exit_xml2_xmlreader();
pike_exit_xml2_stylesheet();
pike_exit_xml2_sax();
pike_exit_xml2_node();
pike_exit_xml2_html();
pike_exit_xml2_constants();
#ifdef HAVE_XSLT
xsltCleanupGlobals();
#endif /* HAVE_XSLT */
xmlCleanupParser();
}
/*! @endmodule
*/
/*! @endmodule
*/
/*! @endmodule
*/