
Some projects use XSLT as the main “engine” of templates. In addition to the well-known flaws of XSLT (for example, its verbosity, relative slowness, etc.) it also has advantages: the “standard” of the language, its ideology of the absence of “side effects” and pattern matching, the ability to call methods of helper classes from templates (via exslt extension). Some time ago I laid out the
ShortXSLT library, allowing instead of cumbersome <xsl: value-of-select = "/ root / abc" /> and <xsl: choose> ... </ xsl: choose> to write simply {/ root / abc} and {if ...} ... {elseif} ... {/ if} without losing performance, so the verbosity problem is partly solved.
But now it’s not about the advantages and disadvantages of XSLT (I’m sure both opponents and supporters of this technology will be abundant). I would like to describe one trick that is convenient to use in
existing projects with XSLT templates, and provide a link to the library that implements this trick with good performance.
Passing data to XSLT, bypassing the generation of XML text representation
Imagine that we have a controller that generates some nested PHP list of objects to display on the page. It should convert this array to XML, which then goes to the input XSLT-template. It would be good if this conversion from PHP to XML structures was not performed manually in each controller, but there was some intermediate layer of abstraction that can apply the XSLT template directly to PHP data, bypassing the XML text representation. So we will reduce the likelihood of errors, and the letter will be reduced. We can work with XSLT templates directly, bypassing the XML representation of the data.
')
Some time ago I wrote the PHP
dom_varimport extension in
C (also
posted on GitHub ). It contains the function of the same name, the input of which is the DOMDocument object and the PHP array of any nesting. The function fills the DOMDocument passed to it with the XML representation of the input array, and it does it very quickly — about
20 times faster than the code written in pure PHP would do. A large document about 1 MB in size with thousands of nested properties and objects is formed in about 1-2 milliseconds.
For example, call:
$ doc = new DOMDocument ();
dom_varimport (
$ doc,
array (
"some_key" => 111,
123,
0.5,
"arr" => array ("1a" => "1a"),
"obj" => (object) array ("prop" => "val"),
true
false,
"b" => null,
"empty" => array (),
),
"root" // optional, defaults to "root"
);
$ doc-> formatOutput = true;
echo $ doc-> saveXML (); // this is for debugging only: in practice, you will not need to call saveXML ()
will print this XML document:
<? xml version = "1.0"?>
<root>
<some_key key = "some_key"> 111 </ some_key> <! - plain key = value ->
<item key = "0"> 123 </ item> <! - numeric keys are "item" tags ->
<item key = "1"> 0.5 </ item> <! - double ->
<arr key = "arr"> <! - nested array ->
<item key = "1a"> 1a </ item> <! - invalid tag names are converted to "item" ->
</ arr>
<obj key = "obj"> <! - nested object ->
<prop key = "prop"> val </ prop>
</ obj>
<item key = "2"> 1 </ item> <! - true converts to 1 ->
<item key = "3" /> <! - false converts to an empty string ->
<b key = "b" /> <! - null also converts to an empty string ->
<empty key = "empty" /> <! - empty array is an empty element ->
</ root>
Everything is quite transparent: the array keys and properties of the objects become XML elements, possibly with the same names (but if the name is invalid for the XML element, then “item” is used instead). Such an XML document is very easy to read when debugging, it is very compact. So, we get the output of a DOMDocument object, which we can already pass to the XSLTProcessor. The textual representation of XML does not appear anywhere, does not parse anywhere.
How to install the extension
The extension is written in C, so you need to compile it on a machine that has GCC installed and packages like php5-src (or php5-devel). This is not at all scary:
git clone https://github.com/DmitryKoterov/dom_varimport.git
cd dom_varimport
phpize
./configure
make
make test
make install # or copy modules / dom_varimport.so manually
phpize - clean
The “make install” stage can be avoided: just take the modules / dom_varimport.so binary file and copy it to a directory with PHP extensions (for example, / usr / lib / php5), including on other machines. Finally, you need to enable the extension in /etc/php5/conf.d/dom_varimport.ini and restart php5-fpm or apache:
extension = /usr/lib/php5/dom_varimport.so