Home modules.gotpike.org
Username: Password: [Create Account]
[Forgot Password?]

Modules

ADT
Database
GTK2
GUI
IP
PiJAX
Public
Sql
Stdio
Subversion
System
Tools
Xosd
lua
v4l2
wx

Recent Changes

Public.Parser.XML2 1.50
Public.ZeroMQ 1.1
Public.Template.Mustache 1.0
Public.Protocols.XMPP 1.4
Sql.Provider.jdbc 1.0

Popular Downloads

Public.Parser.JSON2 1.0
Public.Parser.JSON 0.2
GTK2 2.23
Public.Web.FCGI 1.8
Public.Parser.XML2 1.48


Module Information
Public.Parser.XML2
Viewing contents of Public_Parser_XML2-1.42/Stylesheet.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: Stylesheet.cmod,v 1.21 2008-01-14 23:36:26 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 
 *
 * 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:
 *
 *
 */

#define THIS_IS_XML2_STYLESHEET 1

#include "xml2.h"

/*! @module Public
 */

/*! @module Parser
 */

/*! @module XML2
 */

/*! @class Stylesheet
 */

PIKECLASS Stylesheet
optflags ID_PRIVATE;
program_flags PROGRAM_USES_PARENT;
{

  CVAR STYLESHEET_OBJECT_DATA   *object_data;
  PIKEVAR object node;

  PIKEVAR function docloader
  optflags ID_STATIC;

  void my_xsltGenericErrorFunc(void * ctx, const char *msg, ...)
  {
    va_list args;

    va_start(args,msg);
    vprintf(msg, args);
    va_end(args);
  }

/*! @decl void set_docloader(function f)
 *!
 *! sets the xslt loader function. this is local to the stylesheet.
 *!
 *! the callout should have the following signature:
 *!
 *!  Node f(string uri, int options, int type)
 *!
 *!  where:
 *!    uri is the URI of the document to load
 *!    options are a set of xmlParserOption
 *!    the xsltLoadType indicating the kind of loading required
 */
PIKEFUN void set_docloader(function f)
{
  /* TODO: we probably have a memory leak here... */
  assign_svalue(&(THIS->docloader), f);
#ifdef HAVE_XSLTSETLOADERFUNC
#else
  Pike_error("set_docloader not available. upgrade your libxslt.\n");
#endif
  pop_stack();
}

/*! @decl void clear_docloader()
 *!
 *! clears the stylesheet docloader callout, if one was set.
 *!
 */
PIKEFUN void clear_xslt_docloader()
{

  /* TODO: we probably have a memory leak here... */
  push_int(0);
  assign_svalue(&(THIS->docloader), Pike_sp-1);
#ifdef HAVE_XSLTSETLOADERFUNC
#else
  Pike_error("set_docloader not available. upgrade your libxslt.\n");
#endif
}

  
/* 

   The pike - docloader callback glue
  
 */
xmlDocPtr pike_docloader_conv (const xmlChar * URI, xmlDictPtr dict, 
                               int options, void * ctxt, int type)
{
    struct Node_struct * ns;
    NODE_OBJECT_DATA * od;
    struct object * xnode;

    stack_dup();
    push_text(URI);
    push_int(options);
    push_int(type);
    apply_svalue(&Pike_sp[0-4], 3);

    if(Pike_sp[0-1].type != T_OBJECT)
      return NULL;

    CHECK_NODE_PASSED(Pike_sp[0-1].u.object);
    add_ref(Pike_sp[0-1].u.object);
    ns = OBJ2_NODE(Pike_sp[0-1].u.object);
    od = (NODE_OBJECT_DATA *)(ns->object_data);

    pop_stack();

    if(od->node->doc == NULL)
      return NULL;    
    else return od->node->doc;

    return NULL;
}

PIKEFUN string _sprintf(int type, mixed t)
{
  char * desc;

  check_stylesheet_created();
  
  push_text("Stylesheet()");
}

PIKEFUN void create()
{
}

/*! @decl Node apply(Node xml, mapping|void attributes)
 *!
 *! apply the stylesheet object to an xml file.
 *!
 *! @param xml
 *!   a @[Node] object from the parsed XML document to apply.
 *!   Any node from the XML document may be used.
 *!
 *! @param attributes
 *!   an optional mapping of attributes. If supplied, this parameter
 *!   will override any set with @[set_attributes()].
 *!
 *! @returns
 *!    a @[Node] object for the transformed document.
 */
PIKEFUN object apply(object xml)
{
  CHECK_NODE_PASSED(xml);

  low_apply_stylesheet(args, xml, THIS->object_data->atts);
}

/*! @decl string output_type()
*/
PIKEFUN string output_type()
{
  if(THIS->object_data->stylesheet == NULL)
    push_int(0);
  else 
  {
    if(THIS->object_data->stylesheet->method != NULL)
      push_text(THIS->object_data->stylesheet->method);
    else
      push_text("xml");
  }
}

/*! @decl string media_type()
*/
PIKEFUN string media_type()
{
  if(THIS->object_data->stylesheet == NULL)
    push_int(0);
  else 
  {
    if(THIS->object_data->stylesheet->mediaType != NULL)
      push_text(THIS->object_data->stylesheet->mediaType);
    else
      push_int(0);
  }
}

PIKEFUN object apply(object xml, mapping attributes)
{

  char** vars = NULL;
  int i = 0;

  CHECK_NODE_PASSED(xml);

  vars = low_set_attributes(attributes);

  low_apply_stylesheet(args, xml, (const char **)vars);
}

void low_apply_stylesheet(INT32 args, struct object * xml, const char ** atts)
{
  int i;
  xmlDocPtr output;
  struct Node_struct * ns;
  NODE_OBJECT_DATA * od;
  struct object * xnode;
  int have_func = 0;
  int x=0;
  struct external_variable_context loc;

  if(atts!=NULL)
  for(i =0;; i=i+2)
  {
    if((atts[i]) == NULL) break;
/*    printf("%s: %s\n", (atts[i]), (atts[i+1])); */
  }  

#ifdef HAVE_XSLTSETLOADERFUNC
    push_svalue(&THIS->docloader);  

    if(Pike_sp[0-1].type == T_FUNCTION)
    {
      have_func = 1;
      xsltSetLoaderFunc(pike_docloader_conv);
    }
    else
    {
      pop_stack();
      xsltSetLoaderFunc(NULL);
    }
#endif
 

  output = xsltApplyStylesheet(THIS->object_data->stylesheet, 
                                 OBJ2_NODE(xml)->object_data->node->doc, 
                                 atts);

  // we pushed the stack, so let's pop it.
  if(have_func)
  {
    pop_stack();
  }

  if(output == NULL)
  {
    pop_n_elems(args);
    Pike_error("unable to transform document.\n");
  }

  xnode = NEW_NODE();
  ns = OBJ2_NODE((xnode));
  od = (NODE_OBJECT_DATA *)(ns->object_data);

  od->refs = malloc(sizeof(INT32));
  (* od->refs)=1;

  if(output->children == NULL)
  {
    Pike_error("unable to find a node for the document.\n");
  }
  od->node = output->children;

  pop_stack();
  push_object(xnode);
}

/*! @decl string output(Node xml, int|void encoding)
 *!
 *!   render the applied stylesheet Node to a string.
 *!
 *! @param xml
 *!   the transformed xml object
 *! 
 *! @param encoding
 *!   an optional encoding for the string. if not supplied, defaults to 
 *!   ISO-8859-1 (ISO Latin 1). Valid options are found in 
 *!   @[Public.XML2.Constants], XML_CHAR_ENCODING*.
 *!
 *! @returns
 *!   the string representation of the transformed XML.
 */
PIKEFUN string output(object xml)
{
  xmlOutputBufferPtr xmlBuf;
  xmlCharEncodingHandlerPtr encoder;

  CHECK_NODE_PASSED(xml);
  encoder = xmlGetCharEncodingHandler((xmlCharEncoding)10);
 
  if(encoder == NULL) 
    Pike_error("unable to obtain encoder.\n");

  xmlBuf = xmlAllocOutputBuffer(encoder);

  xsltSaveResultTo( xmlBuf, OBJ2_NODE(xml)->object_data->node->doc, 
                       THIS->object_data->stylesheet);

  pop_n_elems(args);

  push_text(xmlBuf->conv->content);

  xmlOutputBufferClose(xmlBuf);
}

PIKEFUN string output(object xml, int encoding)
{
  xmlOutputBufferPtr xmlBuf;
  xmlCharEncodingHandlerPtr encoder;

  CHECK_NODE_PASSED(xml);
  encoder = xmlGetCharEncodingHandler((xmlCharEncoding)encoding);

  if(encoder == NULL)
    Pike_error("unable to obtain encoder.\n");

  xmlBuf = xmlAllocOutputBuffer(encoder);

  xsltSaveResultTo( xmlBuf, OBJ2_NODE(xml)->object_data->node->doc, 
                       THIS->object_data->stylesheet);

  pop_n_elems(args);

  push_text_len(xmlBuf->conv->content, xmlBuf->conv->use);

  xmlOutputBufferClose(xmlBuf);
}

/*! @decl void set_attributes(mapping variables)
 *!
 *! set attributes for use by the stylesheet transformation
 *!
 *! @note
 *!  Currently, the input to this function is assumed to be UTF-8 encoded.
 *!  We should probably do that automagically.
 */
PIKEFUN void set_attributes(mapping variables)
{
  int i;
  char** vars = NULL;
  vars = low_set_attributes(variables);
  THIS->object_data->atts = (const char **)vars;
  pop_stack();
  
}

char** low_set_attributes(struct mapping * variables)
{

  int varcount, i;
  struct keypair * k;
  INT32 e;
  xmlChar* value;
  char ** vars = NULL;
  const xmlChar* str;

  if ( variables != NULL ) 
  {
    struct svalue sind, sval;
    int tmpint=0;

    varcount = 0;

    if(THIS->object_data->atts != NULL)
    {
      free(THIS->object_data->atts);
      THIS->object_data->atts = NULL;
    }
    vars = malloc( sizeof(char *) * 
                  ( 1 + ((m_sizeof(variables)) * 2 )));
    MAPPING_LOOP(variables)  
    {
      sind = k->ind;
      sval = k->val;
      if(!(sind.type == T_STRING && sval.type == T_STRING)) 
      {
        continue;
      }
      // index
printf("name %s, value %s\n", sind.u.string->str, sval.u.string->str);
      str  = (const xmlChar *) sval.u.string->str;
      if ( xmlStrstr(str, (xmlChar*) "\n") == NULL ) 
      {
        if ( xmlStrchr(str, '"') ) 
        {
          if (xmlStrchr(str, '\'')) 
          {
            Pike_error("Param contains quote and double-quotes.");
            return;    
          }
          value = xmlStrdup((const xmlChar *)"'");
          value = xmlStrcat(value, str);
          value = xmlStrcat(value, (const xmlChar *)"'");
        }
        else 
        {
          value = xmlStrdup((const xmlChar *)"\"");
          value = xmlStrcat(value, str);
          value = xmlStrcat(value, (const xmlChar *)"\"");
        }              
      }
      else 
      {
        // param contains newlines
        value = xmlStrdup((const xmlChar *)"\"");
        value = xmlStrcat(value, (const xmlChar *)"\"");
      }
            
      str = (const xmlChar*) sind.u.string->str;

      // namespaces are bad
      if ( xmlStrchr(str, ':') ) 
        vars[tmpint++] = strdup("supressed");
      else
        vars[tmpint++] = strdup(str);
      vars[tmpint++] = value;
      if ( varcount > MAX_PARAMS )
        Pike_error("Too many params !");
      varcount++;
    }
    vars[tmpint] = NULL;
  }
  else 
  {
    vars = malloc(sizeof(char *));
    vars[0] = NULL;
  }

  for(i =0;; i=i+2)
  {
    if((vars[i]) == NULL) break;
    printf("%s: %s\n", (vars[i]), (vars[i+1]));
  }  
  return vars;
}

int check_stylesheet_created()
{
  if(THIS->object_data->stylesheet != NULL)
    return 1;
  Pike_error("Stylesheet not initialized.\n");
}

INIT
{
  STYLESHEET_OBJECT_DATA * dta;
  xmlGenericErrorFunc my_error;

  dta = 
	(STYLESHEET_OBJECT_DATA*)malloc(sizeof(STYLESHEET_OBJECT_DATA));
    if (!dta)
        Pike_error("init_stylesheet: Out of memory!\n");

    dta->stylesheet = NULL;
    dta->atts = NULL;
    THIS->object_data = dta;

    my_error = my_xsltGenericErrorFunc; 
    xsltSetGenericErrorFunc(NULL, my_error);

}

EXIT
{ 

  if((* THIS->object_data->refs)==1 && THIS->object_data->stylesheet != NULL)
  {
    // we do this to trick xsltFreeStylesheet into not freeing the document.
    // this should prevent a segfault when two stylesheet objects are created
    // from the same xml document.
    THIS->object_data->stylesheet->doc = NULL;
    xsltFreeStylesheet(THIS->object_data->stylesheet);
  }
  else
  {
   (*( THIS->object_data->refs)) --;
  }

  if(THIS->object_data->atts != NULL)
  {
    free(THIS->object_data->atts);
  }

  if(THIS->node != NULL)
  {
// FIXME: this is a memory leak!!!
    free_object(THIS->node);
  }

   if(THIS->object_data)
  {
    free(THIS->object_data);
  }
}
}
/*! @endclass
 */


/*! @endmodule
 */

/*! @endmodule
 */

/*! @endmodule
 */


void pike_init_xml2_stylesheet()
{
  INIT
}

void pike_exit_xml2_stylesheet()
{
  EXIT
}


gotpike.org | Copyright © 2004 - 2019 | Pike is a trademark of Department of Computer and Information Science, Linköping University