 |
Smarty
The discussions here are for Smarty, a template engine for the PHP programming language. Dedicated server web hosting provided by Guru-host.eu. |
| View previous topic :: View next topic |
| Author |
Message |
hdkeeper Smarty Rookie

Joined: 20 Nov 2008 Posts: 13
|
Posted: Thu Nov 20, 2008 8:02 pm Post subject: Smarty XSLT block function |
|
|
Here's an example of quick and dirty XSLT plugin for Smarty 2.6.20. It supports PHP arrays, classes and raw XML as data source. Support for different encodings is also present. This plugin requires PHP-5 with DOM & XSL extensions, and PEAR::XML_Serializer class. Sorry, no version for PHP-4 yet.
plugins/block.xslt.php
| Code: | <?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/
/**
* Smarty {xslt}{/xslt} block plugin
*
* Type: block function<br>
* Name: xslt<br>
* Purpose: Apply recursive transformations to complex data structures like
* nested array, classes, trees etc. Usage for simple data structures
* will end with great pain in the ass!<br>
* Requires: PHP-5, DOM and XSL extensions, PEAR::XML_Serializer<br>
*
* @author Keeper <hd_keeper at mail dot ru>
* @param array $params
* <pre>
* Params: from: mixed - array or class containing source data to display,
* not used if 'from_xml' was provided
* from_xml: string - XML containing source data to display
* assign_xml: string - template variable the intermediate XML will be
* assigned to (useful for debugging)
* encoding: string - character set to use (UTF-8 by default)
* defaultTagName: string - default name for tags (see XML_Serializer)
* rootName: string - name of the root tag (see XML_Serializer)
*
* Any other parameters will be passed as options to XML_Serializer
* You should provide either 'from' or 'fromxml' parameter!
* </pre>
* @param string $content - XSLT template to apply
* @param Smarty $smarty - clever simulation of a method
* @return string - generated HTML/XML data
*/
function smarty_block_xslt( $params, $content, &$smarty)
{
if (is_null( $content)) {
return;
}
// Setup default parameters
$from = null;
$from_xml = null;
$assign_xml = null;
$encoding = null;
$xml_serializer_options = array(
'addDecl' => true,
'classAsTagName' => true,
);
// Obtain provided parameters
foreach ($params as $_key => $_val) {
switch ($_key) {
case 'from':
case 'from_xml':
case 'assign_xml':
$$_key = $_val;
break;
case 'encoding':
$$_key = $xml_serializer_options[ $_key] = $_val;
break;
default:
$xml_serializer_options[ $_key] = $_val;
break;
}
}
// Validate provided parameters
if (is_null( $from) && is_null( $from_xml)) {
$smarty->trigger_error( "xslt: either 'from' or 'fromxml' attribute should be provided", E_USER_ERROR);
}
// Format intermediate XML-data if not provided
if (is_null( $from_xml)) {
require_once 'XML/Serializer.php';
$serializer = new XML_Serializer( $xml_serializer_options);
$serializer->serialize( $from);
$from_xml = $serializer->getSerializedData();
if (!is_null( $assign_xml)) {
$smarty->assign( $assign_xml, $from_xml);
}
}
// Load XML-data and XSLT-template into DOM documents
$dom_data = new DOMDocument( '1.0', $encoding);
$dom_data->loadXML( $from_xml);
$dom_template = new DOMDocument( '1.0', $encoding);
$dom_template->loadXML( $content);
// Transform XML-data to format the output XML/HTML
$_output = '';
$processor = new XSLTProcessor();
$processor->importStyleSheet( $dom_template);
$_output = $processor->transformToXML( $dom_data);
return $_output;
}
?> |
|
|
| Back to top |
|
 |
hdkeeper Smarty Rookie

Joined: 20 Nov 2008 Posts: 13
|
Posted: Thu Nov 20, 2008 8:14 pm Post subject: |
|
|
Now some stuff to test this plugin.
test.php
| Code: | <?php
require_once 'Smarty/Smarty.class.php';
$smarty = new Smarty();
$smarty->template_dir = $_SERVER['DOCUMENT_ROOT'].'/';
$smarty->compile_dir = $_SERVER['DOCUMENT_ROOT'].'/templates_c/';
$smarty->cache_dir = $_SERVER['DOCUMENT_ROOT'].'/cache/';
// Use arrays as data source
$list = array(
array(
'id' => rand( 0, 1000),
'name' => 'File',
'child_list' => array(
array(
'id' => rand( 0, 1000),
'name' => 'Open',
'child_list' => array(),
),
array(
'id' => rand( 0, 1000),
'name' => 'Save',
'child_list' => array(),
),
array(
'id' => rand( 0, 1000),
'name' => 'Close',
'child_list' => array(),
),
array(
'id' => rand( 0, 1000),
'name' => 'Exit',
'child_list' => array(),
)
)
),
array(
'id' => rand( 0, 1000),
'name' => 'Edit',
'child_list' => array(
array(
'id' => rand( 0, 1000),
'name' => 'Cut',
'child_list' => array(),
),
array(
'id' => rand( 0, 1000),
'name' => 'Copy',
'child_list' => array(),
),
array(
'id' => rand( 0, 1000),
'name' => 'Paste',
'child_list' => array(),
),
array(
'id' => rand( 0, 1000),
'name' => 'Delete',
'child_list' => array(),
)
)
),
array(
'id' => rand( 0, 1000),
'name' => 'View',
'child_list' => array()
)
);
// Use classes as data source
class EmptyClass {}
class Node
{
public $id; // integer identifier
public $name; // Name of this node
public $child_list; // array of Tree or Node class
function __construct( $name = '') {
$this->id = rand( 0, 1000);
$this->name = $name;
$this->child_list = array();
}
function __destruct() {
foreach ($this->child_list as $child)
unset( $child);
}
function addChild( &$child) {
$this->child_list[] = $child;
}
} // class Node
class Tree extends Node {}
$tree = new Tree('Menu');
$node = array();
foreach (array('File','Edit','View') as $name)
$tree->addChild( $node[$name] = new Node($name));
foreach (array('Open','Save','Close','Exit') as $name)
$node['File']->addChild( new Node($name));
foreach (array('Cut','Copy','Paste','Delete') as $name)
$node['Edit']->addChild( new Node($name));
// Use XML as data source
$xml = '<Tree>
<id>0</id>
<name>Menu</name>
<child_list>
<Node>
<id>1</id>
<name>File</name>
<child_list>
<Node>
<id>11</id>
<name>Open</name>
</Node>
<Node>
<id>12</id>
<name>Save</name>
</Node>
<Node>
<id>13</id>
<name>Close</name>
</Node>
<Node>
<id>14</id>
<name>Exit</name>
</Node>
</child_list>
</Node>
<Node>
<id>2</id>
<name>Edit</name>
<child_list>
<Node>
<id>21</id>
<name>Cut</name>
</Node>
<Node>
<id>22</id>
<name>Copy</name>
</Node>
<Node>
<id>23</id>
<name>Paste</name>
</Node>
<Node>
<id>24</id>
<name>Delete</name>
</Node>
</child_list>
</Node>
<Node>
<id>3</id>
<name>View</name>
</Node>
</child_list>
</Tree>';
// Assign all data and display
$smarty->assign( 'ARRAY_DATA', $list);
$smarty->assign( 'CLASS_DATA', $tree);
$smarty->assign( 'XML_DATA', $xml);
$smarty->display( 'test.tpl');
?> |
|
|
| Back to top |
|
 |
hdkeeper Smarty Rookie

Joined: 20 Nov 2008 Posts: 13
|
Posted: Thu Nov 20, 2008 8:20 pm Post subject: |
|
|
| Damn, I cannot post HTML/XML code yet... -_- |
|
| Back to top |
|
 |
hdkeeper Smarty Rookie

Joined: 20 Nov 2008 Posts: 13
|
Posted: Thu Nov 20, 2008 8:21 pm Post subject: |
|
|
Smarty template with XSLT included.
test.tpl
| Code: | <html>
<head>
<title>Smarty XSLT block plugin</title>
</head>
<body>
<h1>Smarty XSLT block plugin</h1>
<h2>Using data from arrays</h2>
{xslt from=$ARRAY_DATA defaultTagName="Node" rootName="child_list" assign_xml="DEBUG_XML_ARRAY"}
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="KOI8-R" indent="yes"/>
<xsl:template match="child_list">
<ul>
<xsl:for-each select="Node">
<li>
<a>
<xsl:attribute name="href">
<xsl:value-of select="id"/>
</xsl:attribute>
<xsl:value-of select="name"/>
</a>
<xsl:apply-templates select="child_list[ node()]"/>
</li>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>
{/xslt}
<h3>Intermediate XML</h3>
<pre>{$DEBUG_XML_ARRAY|escape}</pre>
<h2>Using data from classes</h2>
{xslt from=$CLASS_DATA assign_xml="DEBUG_XML_CLASS"}
{include file="test.xsl"}
{/xslt}
<h3>Intermediate XML</h3>
<pre>{$DEBUG_XML_CLASS|escape}</pre>
<h2>Using data from XML text</h2>
{xslt from_xml=$XML_DATA}
{include file="test.xsl"}
{/xslt}
<h3>Source XML</h3>
<pre>{$XML_DATA|escape}</pre>
</body>
</html> |
|
|
| Back to top |
|
 |
hdkeeper Smarty Rookie

Joined: 20 Nov 2008 Posts: 13
|
Posted: Thu Nov 20, 2008 8:22 pm Post subject: |
|
|
Standalone XSL template referred from above.
test.xsl
| Code: | <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="KOI8-R" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="Tree">
<xsl:apply-templates select="child_list"/>
</xsl:for-each>
</xsl:template>
<xsl:template match="child_list">
<ul>
<xsl:for-each select="Node">
<li>
<a>
<xsl:attribute name="href">
<xsl:value-of select="id"/>
</xsl:attribute>
<xsl:value-of select="name"/>
</a>
<xsl:apply-templates select="child_list[ node()]"/>
</li>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet> |
|
|
| Back to top |
|
 |
hdkeeper Smarty Rookie

Joined: 20 Nov 2008 Posts: 13
|
Posted: Sun Nov 23, 2008 12:15 pm Post subject: |
|
|
The next version of XSLT plugin for your consideration. No PEAR::XML_Serializer class is longer required, and some speedup is also gained. This version requires PHP-5 with mbstring, DOM & XSL extensions.
plugins/block.xslt.php
| Code: | <?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/
/**
* Smarty {xslt}{/xslt} block plugin
*
* Type: block function<br>
* Name: xslt<br>
* Purpose: Apply recursive transformations to complex data structures like
* nested array, classes, trees etc. Usage for simple data structures
* will end with great pain in the ass!<br>
* Requires: PHP-5 with MBString, DOM, XSL extensions<br>
*
* @author Keeper <hd_keeper at mail dot ru>
* @param array $params
* <pre>
* Params: from: mixed - array or class containing source data to display,
* ignored if 'from_xml' was provided
* from_xml: string - XML containing source data to display
* assign_xml: string - template variable the intermediate XML will be
* assigned to (useful for debugging)
* root_tag: string - name for the root element (default "root")
* default_tag: string - default name for tags (default "data")
* key_attribute: string - attribute name for array keys (default none)
* encoding: string - character set to use (default "UTF-8")
*
* You should provide either 'from' or 'from_xml' parameter!
* </pre>
* @param string $content - XSL-template to apply
* @param Smarty $smarty - clever simulation of a method
* @return string - generated HTML/XML data
*/
function smarty_block_xslt( $params, $content, &$smarty)
{
if (is_null( $content)) {
return;
}
// Setup default parameters
$from = null;
$from_xml = null;
$assign_xml = null;
$opts = array(
'root_tag' => "root",
'default_tag' => "data",
'key_attribute' => null,
'encoding' => "UTF-8"
);
// Obtain provided parameters
foreach ($params as $_key => $_val) {
switch ($_key) {
case 'from':
case 'from_xml':
case 'assign_xml':
$$_key = $_val;
break;
case 'root_tag':
case 'default_tag':
case 'key_attribute':
case 'encoding':
$opts[ $_key] = $_val;
break;
default:
$smarty->trigger_error( "xslt: unknown attribute '$_key'");
}
}
// Create DOM ducument containing provided data
$dom_data = new DOMDocument( '1.0', $opts['encoding']);
if (!is_null( $from_xml)) {
// Load provided raw XML-data into DOM document
$dom_data->loadXML( $from_xml);
} elseif (!is_null( $from)) {
// Build DOM document from provided source data
mb_regex_encoding( $opts['encoding']);
smarty_block_xslt_append( $dom_data, $opts['root_tag'], $from, $opts);
} else {
$smarty->trigger_error( "xslt: either 'from' or 'fromxml' attribute should be provided", E_USER_ERROR);
}
// Assign intermediate XML-data to the template variable
if (!is_null( $assign_xml)) {
$from_xml = $dom_data->saveXML();
$smarty->assign( $assign_xml, $from_xml);
}
// Create DOM document containing provided XSL-template
$dom_template = new DOMDocument( '1.0', $opts['encoding']);
$dom_template->loadXML( $content);
// Transform XML-data to make an output XML/HTML
$_output = "";
$processor = new XSLTProcessor();
$processor->importStyleSheet( $dom_template);
$_output = $processor->transformToXML( $dom_data);
return $_output;
}
/**
* Recursively walk through the provided variable,
* append all found data to the DOM document
*
* @access private
* @param DOMNode $dom_node - XML-element the childs are to be appended to
* @param string $use_key - suggested key to be used as tag name
* @param mixed $data - variable to be stored in the DOM document
* @param array $opts - set of immutable options
* @return void
*/
function smarty_block_xslt_append( DOMNode &$dom_node, $use_key, &$data, &$opts)
{
// For objects, use class name as tags
$use_tag = is_object($data) ? get_class( $data) : $use_key;
// Use default tag name instead of invalid tag names
if (!mb_ereg_match( '^[[:alpha:]_][[:alnum:]:_\.\-]*$', $use_tag))
$use_tag = $opts['default_tag'];
if (is_array($data) || is_object($data)) {
// Add a node for entire array or object
$dom_child = $dom_node->appendChild( new DOMElement(
smarty_block_xslt_conv( $use_tag, $opts)
));
// Enumerate array elements or object properties
foreach ($data as $_key => $_val) {
// Recurrent call for array element or object property
smarty_block_xslt_append( $dom_child, $_key, $_val, $opts);
}
} else {
// Plain data is added as leaf node
$dom_child = $dom_node->appendChild( new DOMElement(
smarty_block_xslt_conv( $use_tag, $opts),
htmlspecialchars( smarty_block_xslt_conv( $data, $opts), ENT_COMPAT, "UTF-8")
));
}
// Store key as attribute if required
if (!empty( $opts['key_attribute'])) {
$dom_child->setAttribute(
smarty_block_xslt_conv( $opts['key_attribute'], $opts),
smarty_block_xslt_conv( $use_key, $opts)
);
}
}
/**
* Convert data string to internal encoding of DOM document (UTF-8)
*
* @access private
* @param string $str - data to be converted
* @param array $opts - set of immutable options
* @return string - data converted to internal encoding
*/
function smarty_block_xslt_conv( $str, &$opts)
{
if (!mb_check_encoding( (string) $str, $opts['encoding']))
trigger_error( "xslt: data string '$str' has invalid encoding", E_USER_WARNING);
return mb_convert_encoding( (string) $str, "UTF-8", $opts['encoding']);
}
?> |
Last edited by hdkeeper on Thu Dec 25, 2008 10:31 am; edited 4 times in total |
|
| Back to top |
|
 |
hdkeeper Smarty Rookie

Joined: 20 Nov 2008 Posts: 13
|
Posted: Sun Nov 23, 2008 12:18 pm Post subject: |
|
|
As names of parameters for the plugin were changed, we have to change our testing template, too.
test.tpl
| Code: | <html>
<head>
<title>Smarty XSLT block plugin</title>
</head>
<body>
<h1>Smarty XSLT block plugin</h1>
<h2>Using data from arrays</h2>
{xslt from=$ARRAY_DATA root_tag="child_list" default_tag="Node" assign_xml="DEBUG_XML_ARRAY"}
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="KOI8-R" indent="yes"/>
<xsl:template match="child_list">
<ul>
<xsl:for-each select="Node">
<li>
<a>
<xsl:attribute name="href">
<xsl:value-of select="id"/>
</xsl:attribute>
<xsl:value-of select="name"/>
</a>
<xsl:apply-templates select="child_list[ node()]"/>
</li>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>
{/xslt}
<h3>Intermediate XML</h3>
<pre>{$DEBUG_XML_ARRAY|escape}</pre>
<h2>Using data from classes</h2>
{xslt from=$CLASS_DATA assign_xml="DEBUG_XML_CLASS"}
{include file="test.xsl"}
{/xslt}
<h3>Intermediate XML</h3>
<pre>{$DEBUG_XML_CLASS|escape}</pre>
<h2>Using data from XML text</h2>
{xslt from_xml=$XML_DATA}
{include file="test.xsl"}
{/xslt}
<h3>Source XML</h3>
<pre>{$XML_DATA|escape}</pre>
</body>
</html> |
|
|
| Back to top |
|
 |
hdkeeper Smarty Rookie

Joined: 20 Nov 2008 Posts: 13
|
Posted: Thu Dec 25, 2008 10:30 am Post subject: |
|
|
| Some bugfixes were applied to plugins/block.xslt.php -- see above. |
|
| Back to top |
|
 |
kannan Smarty n00b
Joined: 27 Feb 2009 Posts: 1
|
Posted: Fri Feb 27, 2009 4:49 pm Post subject: Smarty with xml |
|
|
| Can anyone please help me in writing a simple smarty code with an xml code as the template and the template xml code having a corresponding xslt.I am a beginner |
|
| Back to top |
|
 |
hdkeeper Smarty Rookie

Joined: 20 Nov 2008 Posts: 13
|
Posted: Tue Mar 31, 2009 4:27 pm Post subject: |
|
|
Well... There were some simple samples of XML/XSLT code above, and examples of Smarty plugin invocation, too.
What goal you are going to achieve? What your code should display? |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|
|