mirror of
https://github.com/php/php-src.git
synced 2026-04-16 12:31:06 +02:00
Add a readme, this is a substitute to the e-mail I was going to send. it
gives a basic overview of the new xslt extension and goes into the details of the api, etc.
This commit is contained in:
281
ext/xslt/README.XSLT-BACKENDS
Normal file
281
ext/xslt/README.XSLT-BACKENDS
Normal file
@@ -0,0 +1,281 @@
|
||||
+------------------------------------------------------------------------------+
|
||||
| CREATING XSLT BACKENDS |
|
||||
+------------------------------------------------------------------------------+
|
||||
|
||||
Author(s): Sterling Hughes <sterling@php.net>
|
||||
|
||||
Introduction
|
||||
-------------------------------------------------------------------------------
|
||||
Truth be told, at this point in time there are about a zillion and two
|
||||
different XSLT libraries, each with there unique merits and faults. If you
|
||||
provide a Sablotron extension, people will clamor for a Xalan extension, if you
|
||||
provide a Xalan extension people will clamor for a libxslt extension.
|
||||
|
||||
In order to be as user friendly as possible, we try and provide the most
|
||||
amount of options to the user. At the same time we must try to keep a level of
|
||||
consistency, so the user does not need to remember 15 different syntaxes, etc.
|
||||
for each XSLT extension, and when switching from XSLT backends, no changes in
|
||||
the PHP code should be necessary (akin to the concept of a database independent
|
||||
api, but with XSLT libraries).
|
||||
|
||||
At the same time, you'll also notice that in some cases extensions seem to
|
||||
duplicate each others functionality. All extensions need code for calling
|
||||
user-defined handlers, omitting debug messages, etc. In the interests of
|
||||
laziness, we must also try to make these as minimal as possible.
|
||||
|
||||
Therefore, I've create a processor independent api for XSLT, aka, the XSLT
|
||||
extension (but doesn't "A processor independent API for XSLT" sound cooler?).
|
||||
It defines a set of functions which every XSLT backend must provide, as well
|
||||
as a syntax which those functions must adhere to. Furthermore, the underlying
|
||||
code, provides a "library" if you will, of code that is relevant to all XSLT
|
||||
extensions.
|
||||
|
||||
The API
|
||||
-------------------------------------------------------------------------------
|
||||
Every extension must define the following functions:
|
||||
|
||||
- xslt_create()
|
||||
- xslt_set_scheme_handlers()
|
||||
- xslt_set_sax_handlers()
|
||||
- xslt_set_error_handler()
|
||||
- xslt_set_log()
|
||||
- xslt_process()
|
||||
- xslt_error()
|
||||
- xslt_errno()
|
||||
- xslt_free()
|
||||
|
||||
These functions are common or implementable with every single XSLT library that
|
||||
I've come across so far (at least every C library) and should there for be
|
||||
defined by the extension.
|
||||
|
||||
|
||||
resource xslt_create(void)
|
||||
|
||||
The XSLT create function allocates a new XSLT processor and returns a resource
|
||||
pointer to the XSLT processor. It also handles any initialization that the
|
||||
processor requires.
|
||||
|
||||
|
||||
void xslt_set_scheme_handlers(resource processor, array handlers)
|
||||
|
||||
Registers the scheme handlers for the document (aka XPath handlers), given a
|
||||
XSLT processor resource (allocated by xslt_create()) and an array in the
|
||||
following format:
|
||||
|
||||
array(
|
||||
"get_all" => function,
|
||||
"open" => function,
|
||||
"get" => function,
|
||||
"put" => function,
|
||||
"close" => function
|
||||
)
|
||||
|
||||
Where function is either a function name or an array in the following format:
|
||||
|
||||
array(&$obj, "method")
|
||||
|
||||
Note: The given array does not need to contain all of the different scheme
|
||||
handler elements (although it can), but it only needs to conform to
|
||||
the "handler" => "function" format described above.
|
||||
|
||||
Each of the individual scheme handler functions called are in the formats
|
||||
below:
|
||||
|
||||
string get_all(resource processor, string scheme, string rest)
|
||||
resource open(resource processor, string scheme, string rest)
|
||||
int get(resource processor, resource fp, string &data)
|
||||
int put(resource processor, resource fp, string data)
|
||||
void close(resource processor, resource fp)
|
||||
|
||||
|
||||
void xslt_set_sax_handlers(resource processor, array handlers)
|
||||
|
||||
Registers the SAX handlers for the document, given a XSLT processor resource
|
||||
(allocated by xslt_create()) and an array in the following format:
|
||||
|
||||
array(
|
||||
"document" => array(document_start_function,
|
||||
document_end_function),
|
||||
"element" => array(element_start_function,
|
||||
element_end_function),
|
||||
"namespace" => array(namespace_start_function,
|
||||
namespace_end_function),
|
||||
"comment" => function,
|
||||
"pi" => function,
|
||||
"character" => function
|
||||
)
|
||||
|
||||
Where the functions follow the syntax described for the scheme handler
|
||||
functions.
|
||||
|
||||
Each of the individual SAX handler functions are in the format below:
|
||||
|
||||
void start_doc(resource processor)
|
||||
void end_doc(resource processor)
|
||||
void start_element(resource processor, string name, array attributes)
|
||||
void end_element(resource processor, string name)
|
||||
void start_namespace(resource processor, string prefix, string uri)
|
||||
void end_namespace(resource processor, string prefix)
|
||||
void comment(resource processor, string contents)
|
||||
void pi(resource processor, string target, string contents)
|
||||
void characters(resource processor, string contents)
|
||||
|
||||
|
||||
void xslt_set_error_handler(resource processor, function error_handler)
|
||||
|
||||
This function sets the user defined error handler to be called when a
|
||||
processing or any other type of error occurs. It is given a XSLT
|
||||
processor resource (allocated by xslt_create()) and an error function of
|
||||
the same syntax described for the scheme handler function.
|
||||
|
||||
The user defined error handler as the following syntax:
|
||||
|
||||
void error(resource processor, int level, int error, array info)
|
||||
|
||||
|
||||
void xslt_set_log(resource processor, string logname)
|
||||
|
||||
Sets the XSLT log to record log information (processor messages, not errors).
|
||||
Its given a XSLT processor (allocated by xslt_create()) and a string containing
|
||||
the name of the log file. If the string is "php://stderr" then the logging
|
||||
should go to standard error (stderr). Also the default place to send log
|
||||
messages is standard error (if no log file is set).
|
||||
|
||||
|
||||
mixed xslt_process(resource processor,
|
||||
string xml,
|
||||
string xsl[,
|
||||
string result[,
|
||||
array arguments[,
|
||||
array parameters]]])
|
||||
|
||||
This function performs the magic, it takes the user's data, performs the
|
||||
transformation and depending on the context either saves the result to a file
|
||||
or returns the data to the user.
|
||||
|
||||
To understand the way the xslt_process() function works, you must first
|
||||
understand the concept of "argument buffers". Argument buffers are equivalent
|
||||
to the concept of symlinks on a Unix system, take the following example:
|
||||
|
||||
<?php
|
||||
|
||||
/**
|
||||
* $xml contains the contents of an XML file and $xsl contains
|
||||
* the contents of an XSLT stylesheet
|
||||
*/
|
||||
$args = array("/_xml" => $xml,
|
||||
"/_xsl" => $xsl);
|
||||
|
||||
$xh = xslt_create();
|
||||
$data = xslt_process("arg:/_xml", "arg:/_xsl", NULL, $args);
|
||||
xslt_free($xh);
|
||||
|
||||
print( "The results of the transformation were\n" );
|
||||
print( "<br>\n<hr>\n<br>" );
|
||||
print( $data );
|
||||
print( "<br>\n<hr>\n<br>" );
|
||||
?>
|
||||
|
||||
See what was done? The argument buffer was declared ($args) and the different
|
||||
arguments were defined. Then when the xslt_process() function was called
|
||||
instead of giving the XML filename and XSLT filename we instead gave
|
||||
"arguments", which correspond to the XML and XSLT data in the argument buffers.
|
||||
|
||||
This concept is a bit foreign to some people, however, I find it the best way
|
||||
to handle processing xsl data. If your still having trouble with this, try
|
||||
playing around with the sablotron backend a bit, you should be able to catch on
|
||||
pretty quickly.
|
||||
|
||||
In order to use argument buffers, the XSLT extension provides a couple of easy
|
||||
to use API functions, you can use them as follows:
|
||||
|
||||
{
|
||||
zval **arguments_zp;
|
||||
char **arguments_cp;
|
||||
xslt_args *arguments;
|
||||
char *types[] = { "file", "data" };
|
||||
|
||||
/* Fetch the arguments from the user into a zval ** */
|
||||
|
||||
/* Translate the zval array into a character array */
|
||||
make_xslt_array(&arguments_cp, arguments_zp);
|
||||
|
||||
/* Translate the character array into an xslt_arg * structure */
|
||||
arguments = parse_xslt_arguments(arguments_cp);
|
||||
|
||||
/* Print out the resulting xslt_arg * structure */
|
||||
php_printf("XML type: %s\n", types[arguments->xml.type]);
|
||||
php_printf("XML data: %s\n", arguments->xml.ptr);
|
||||
PUTS("\n");
|
||||
php_printf("XSLT type: %s\n", types[arguments->xsl.type]);
|
||||
php_printf("XSLT data: %s\n", arguments->xsl.ptr);
|
||||
PUTS("\n");
|
||||
php_printf("Result type: %s\n", types[arguments->result.type]);
|
||||
php_printf("Result data: %s\n", arguments->result.ptr);
|
||||
PUTS("\n");
|
||||
}
|
||||
|
||||
You can also test the "type" field by using the XSLT_IS_FILE and XSLT_IS_DATA
|
||||
constants.
|
||||
|
||||
Anyway back to the syntax of the xslt_process() function. The first argument
|
||||
to the xslt_process() function is a resource pointer to the XSLT processor to
|
||||
be used. The second argument is either an "argument buffer" pointing to the
|
||||
XML data or the name of a file containing the XML data. The third argument is
|
||||
either an argument buffer pointing to the XSLT data or a file containing the
|
||||
XSLT data. The fourth argument is optional, it either contains the name of the
|
||||
file to place the results of the transformation into, NULL or "arg:/_result",
|
||||
in the latter 2 cases, the results of the transformation will be returned. The
|
||||
fifth optional argument is the "argument buffer" itself, it is an associative
|
||||
PHP array of "argument_name" => "value" pairs, or NULL, if no arguments are to
|
||||
be passed. The final optional argument is a set of parameters to pass to the
|
||||
XSLT stylesheet. The parameter argument is an associative array of
|
||||
"parameter_name" => "value" pairs.
|
||||
|
||||
|
||||
string xslt_error(resource processor)
|
||||
|
||||
The xslt_error() function returns the last error that occured, given a XSLT
|
||||
processor resource (allocated by xslt_create()).
|
||||
|
||||
|
||||
int xslt_errno(resource processor)
|
||||
|
||||
The xslt_errno() function returns the last error number that occured given a
|
||||
XSLT processor resource (allocated by xslt_create()).
|
||||
|
||||
|
||||
void xslt_free(resource processor)
|
||||
|
||||
The xslt_free() function free's the given XSLT processor resource (allocated
|
||||
by xslt_create()).
|
||||
|
||||
|
||||
Config.m4
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The XSLT extensions "magic" really occurs in the config.m4 file. Here you must
|
||||
add a couple of things in order for your backend to be enabled. Its a bit too
|
||||
complex to describe (but easy to implement and understand). Take a look at
|
||||
config.m4 (which is well commented) to see what is necessary.
|
||||
|
||||
|
||||
Makefile.in
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Simply add the source files for your backend to the LTLIBRARY_SOURCES variable
|
||||
and you're all set with this file.
|
||||
|
||||
|
||||
Conclusion
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Nobody's perfect, I'm sure I've made some mistakes while thinking this whole
|
||||
thing through and I would be glad to here from any of you who think I'm a
|
||||
colossal moron and think you have a better way to do it. Please e-mail at
|
||||
sterling@php.net, this extension will only get better with feedback.
|
||||
|
||||
With that said, the concepts here may take a little bit of time to sink in, I
|
||||
know I've written a whole lot. My suggestion to you, if you're planning on
|
||||
writing an XSLT backend is simply to go off and implement, taking the api
|
||||
section as a guide and making sure you match that api as closely as possible.
|
||||
Reference in New Issue
Block a user