first commit
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/xslt/XMLTypeDescription.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2000-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class XMLTypeDescription
|
||||
*
|
||||
* @ingroup xslt
|
||||
*
|
||||
* @brief Class that describes an XML input/output type.
|
||||
*
|
||||
* Type descriptors follow the syntax:
|
||||
* xml::validation-schema(http://url.to.the/file.{xsd|dtd|rng})
|
||||
*
|
||||
* Example:
|
||||
* xml::schema(http://www.crossref.org/schema/queryResultSchema/crossref_query_output2.0.xsd)
|
||||
*
|
||||
* XML input/output can be either represented as a string or as a DOMDocument object.
|
||||
*/
|
||||
|
||||
namespace PKP\xslt;
|
||||
|
||||
use DOMDocument;
|
||||
use Exception;
|
||||
use PKP\filter\TypeDescription;
|
||||
|
||||
class XMLTypeDescription extends TypeDescription
|
||||
{
|
||||
public const XML_TYPE_DESCRIPTION_VALIDATE_NONE = '*';
|
||||
public const XML_TYPE_DESCRIPTION_VALIDATE_SCHEMA = 'schema';
|
||||
public const XML_TYPE_DESCRIPTION_VALIDATE_DTD = 'dtd';
|
||||
public const XML_TYPE_DESCRIPTION_VALIDATE_RELAX_NG = 'relax-ng';
|
||||
|
||||
/** @var string a validation strategy, see the XML_TYPE_DESCRIPTION_VALIDATE_* constants */
|
||||
public $_validationStrategy = self::XML_TYPE_DESCRIPTION_VALIDATE_SCHEMA;
|
||||
|
||||
/** @var string a validation document as string or filename pointer (xsd or rng only) */
|
||||
public $_validationSource;
|
||||
|
||||
|
||||
//
|
||||
// Setters and Getters
|
||||
//
|
||||
/**
|
||||
* @see TypeDescription::getNamespace()
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return \PKP\filter\TypeDescriptionFactory::TYPE_DESCRIPTION_NAMESPACE_XML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the validation strategy
|
||||
*
|
||||
* @param string $validationStrategy XML_TYPE_DESCRIPTION_VALIDATE_...
|
||||
*/
|
||||
public function setValidationStrategy($validationStrategy)
|
||||
{
|
||||
$this->_validationStrategy = $validationStrategy;
|
||||
}
|
||||
|
||||
//
|
||||
// Implement abstract template methods from TypeDescription
|
||||
//
|
||||
/**
|
||||
* @copydoc TypeDescription::parseTypeName()
|
||||
*/
|
||||
public function parseTypeName($typeName)
|
||||
{
|
||||
// We expect a validation strategy and an optional validation argument
|
||||
$typeNameParts = explode('(', $typeName);
|
||||
switch (count($typeNameParts)) {
|
||||
case 1:
|
||||
// No argument present (only dtd or no validation)
|
||||
$validationStrategy = $typeName;
|
||||
if ($validationStrategy != self::XML_TYPE_DESCRIPTION_VALIDATE_NONE
|
||||
&& $validationStrategy != self::XML_TYPE_DESCRIPTION_VALIDATE_DTD) {
|
||||
return false;
|
||||
}
|
||||
$validationSource = null;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// We have an argument (only available for schema and relax-ng)
|
||||
$validationStrategy = $typeNameParts[0];
|
||||
if ($validationStrategy != self::XML_TYPE_DESCRIPTION_VALIDATE_SCHEMA
|
||||
&& $validationStrategy != self::XML_TYPE_DESCRIPTION_VALIDATE_RELAX_NG) {
|
||||
return false;
|
||||
}
|
||||
$validationSource = trim($typeNameParts[1], ')');
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->_validationStrategy = $validationStrategy;
|
||||
$this->_validationSource = $validationSource;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc TypeDescription::checkType()
|
||||
*/
|
||||
public function checkType($object)
|
||||
{
|
||||
// We only accept DOMDocument objects and source strings.
|
||||
if (!$object instanceof DOMDocument && !is_string($object)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No validation...
|
||||
if ($this->_validationStrategy == self::XML_TYPE_DESCRIPTION_VALIDATE_NONE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Validation - requires DOMDocument
|
||||
if (is_string($object)) {
|
||||
$xmlDom = new DOMDocument('1.0', 'utf-8');
|
||||
$xmlDom->loadXML($object);
|
||||
} else {
|
||||
$xmlDom = & $object;
|
||||
}
|
||||
|
||||
switch ($this->_validationStrategy) {
|
||||
// We have to suppress validation errors, otherwise the script
|
||||
// will stop when validation errors occur.
|
||||
case self::XML_TYPE_DESCRIPTION_VALIDATE_DTD:
|
||||
if (!$xmlDom->validate()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case self::XML_TYPE_DESCRIPTION_VALIDATE_SCHEMA:
|
||||
libxml_use_internal_errors(true);
|
||||
if (!$xmlDom->schemaValidate($this->_validationSource)) {
|
||||
error_log(new Exception("XML validation failed with:\n" . print_r(libxml_get_errors(), true)));
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case self::XML_TYPE_DESCRIPTION_VALIDATE_RELAX_NG:
|
||||
if (!$xmlDom->relaxNGValidate($this->_validationSource)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\xslt\XMLTypeDescription', '\XMLTypeDescription');
|
||||
foreach (['XML_TYPE_DESCRIPTION_VALIDATE_NONE', 'XML_TYPE_DESCRIPTION_VALIDATE_SCHEMA', 'XML_TYPE_DESCRIPTION_VALIDATE_DTD', 'XML_TYPE_DESCRIPTION_VALIDATE_RELAX_NG'] as $constantName) {
|
||||
define($constantName, constant('\XMLTypeDescription::' . $constantName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/xslt/XSLTransformationFilter.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2000-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class XSLTransformationFilter
|
||||
*
|
||||
* @ingroup xslt
|
||||
*
|
||||
* @brief Class that transforms XML via XSL.
|
||||
*/
|
||||
|
||||
namespace PKP\xslt;
|
||||
|
||||
use PKP\filter\FilterGroup;
|
||||
use PKP\filter\FilterSetting;
|
||||
use PKP\filter\PersistableFilter;
|
||||
use PKP\form\validation\FormValidator;
|
||||
|
||||
class XSLTransformationFilter extends PersistableFilter
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param FilterGroup $filterGroup
|
||||
* @param string $displayName
|
||||
*
|
||||
* NB: The input side of the transformation must always
|
||||
* be an XML format. See the XMLTypeDescription class for
|
||||
* more details how to enable XML validation.
|
||||
*/
|
||||
public function __construct($filterGroup, $displayName = 'XSL Transformation')
|
||||
{
|
||||
// Check that we only get xml input, the output type is arbitrary.
|
||||
if (!substr($filterGroup->getInputType(), 0, 5) == 'xml::') {
|
||||
fatalError('XSL filters need XML as input.');
|
||||
}
|
||||
|
||||
// Instantiate the settings of this filter
|
||||
$this->addSetting(new FilterSetting('xsl', null, null));
|
||||
$this->addSetting(new FilterSetting('xslType', null, null));
|
||||
$this->addSetting(new FilterSetting('resultType', null, null, FormValidator::FORM_VALIDATOR_OPTIONAL_VALUE));
|
||||
|
||||
$this->setDisplayName($displayName);
|
||||
|
||||
parent::__construct($filterGroup);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Getters and Setters
|
||||
//
|
||||
/**
|
||||
* Get the XSL
|
||||
*
|
||||
* @return \DOMDocument|string a document, xsl string or file name
|
||||
*/
|
||||
public function &getXSL()
|
||||
{
|
||||
return $this->getData('xsl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the XSL Type
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getXSLType()
|
||||
{
|
||||
return $this->getData('xslType');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the XSL
|
||||
*
|
||||
* @param \DOMDocument|string $xsl
|
||||
*/
|
||||
public function setXSL(&$xsl)
|
||||
{
|
||||
// Determine the xsl type
|
||||
if (is_string($xsl)) {
|
||||
$this->setData('xslType', XSLTransformer::XSL_TRANSFORMER_DOCTYPE_STRING);
|
||||
} elseif ($xsl instanceof \DOMDocument) {
|
||||
$this->setData('xslType', XSLTransformer::XSL_TRANSFORMER_DOCTYPE_DOM);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
$this->setData('xsl', $xsl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the XSL as a file name
|
||||
*
|
||||
* @param string $xslFile
|
||||
*/
|
||||
public function setXSLFilename($xslFile)
|
||||
{
|
||||
$this->setData('xslType', XSLTransformer::XSL_TRANSFORMER_DOCTYPE_FILE);
|
||||
$this->setData('xsl', $xslFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result type
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getResultType()
|
||||
{
|
||||
return $this->getData('resultType');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the result type
|
||||
*
|
||||
* @param int $resultType
|
||||
*/
|
||||
public function setResultType($resultType)
|
||||
{
|
||||
$this->setData('resultType', $resultType);
|
||||
}
|
||||
|
||||
//
|
||||
// Implement template methods from Filter
|
||||
//
|
||||
/**
|
||||
* Process the given XML with the configured XSL
|
||||
*
|
||||
* @see Filter::process()
|
||||
*
|
||||
* @param \DOMDocument|string $xml
|
||||
*
|
||||
* @return \DOMDocument|string
|
||||
*/
|
||||
public function &process(&$xml)
|
||||
{
|
||||
// Determine the input type
|
||||
if (is_string($xml)) {
|
||||
$xmlType = XSLTransformer::XSL_TRANSFORMER_DOCTYPE_STRING;
|
||||
} elseif ($xml instanceof \DOMDocument) {
|
||||
$xmlType = XSLTransformer::XSL_TRANSFORMER_DOCTYPE_DOM;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// Determine the result type based on
|
||||
// the input type if it has not been
|
||||
// set explicitly.
|
||||
if (is_null($this->getResultType())) {
|
||||
$this->setResultType($xmlType);
|
||||
}
|
||||
|
||||
// Transform the input
|
||||
$xslTransformer = new XSLTransformer();
|
||||
$result = $xslTransformer->transform($xml, $xmlType, $this->getXsl(), $this->getXslType(), $this->getResultType());
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\xslt\XSLTransformationFilter', '\XSLTransformationFilter');
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/xslt/XSLTransformer.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2000-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class XSLTransformer
|
||||
*
|
||||
* @ingroup xslt
|
||||
*
|
||||
* @brief Wrapper class for running XSL transformations.
|
||||
*/
|
||||
|
||||
namespace PKP\xslt;
|
||||
|
||||
use DOMDocument;
|
||||
use PKP\config\Config;
|
||||
use PKP\file\FileManager;
|
||||
use XSLTProcessor;
|
||||
|
||||
class XSLTransformer
|
||||
{
|
||||
public const XSLT_PROCESSOR_ENCODING = 'utf-8';
|
||||
public const XSL_TRANSFORMER_DOCTYPE_STRING = 1;
|
||||
public const XSL_TRANSFORMER_DOCTYPE_FILE = 2;
|
||||
public const XSL_TRANSFORMER_DOCTYPE_DOM = 3;
|
||||
|
||||
/** @var string determining the XSLT processor to use for this object */
|
||||
public static $processor;
|
||||
|
||||
/** @var string containing external XSLT shell command */
|
||||
public static $externalCommand;
|
||||
|
||||
/** @var string containing external XSLT shell arguments for parameters */
|
||||
public static $externalParameterSnippet;
|
||||
|
||||
/** @var array of parameters to pass to XSL (built-in libraries only) */
|
||||
public $parameters;
|
||||
|
||||
/** @var array of PHP functions to allow in XSL */
|
||||
public $registerPHPFunctions;
|
||||
|
||||
/** @var array List of error strings */
|
||||
public $errors;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Initialize transformer and set parser options.
|
||||
*
|
||||
* @return bool returns false if no XSLT processor could be created
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Necessary to fetch configuration.
|
||||
self::checkSupport();
|
||||
|
||||
$this->errors = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch configuration and check whether XSLT is properly supported.
|
||||
*
|
||||
* @return bool True iff XSLT support is present.
|
||||
*/
|
||||
public static function checkSupport()
|
||||
{
|
||||
self::$externalCommand = Config::getVar('cli', 'xslt_command');
|
||||
self::$externalParameterSnippet = Config::getVar('cli', 'xslt_parameter_option');
|
||||
|
||||
// Determine the appropriate XSLT processor for the system
|
||||
if (self::$externalCommand) {
|
||||
// check the external command to check for %xsl and %xml parameter substitution
|
||||
if (strpos(self::$externalCommand, '%xsl') === false) {
|
||||
return false;
|
||||
}
|
||||
if (strpos(self::$externalCommand, '%xml') === false) {
|
||||
return false;
|
||||
}
|
||||
self::$processor = 'External';
|
||||
} elseif (extension_loaded('xsl') && extension_loaded('dom')) {
|
||||
// XSL/DOM modules present
|
||||
self::$processor = 'PHP';
|
||||
} else {
|
||||
// no XSLT support
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Getters and Setters
|
||||
//
|
||||
/**
|
||||
* Get the processor type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getProcessor()
|
||||
{
|
||||
return self::$processor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameter list for internal processors.
|
||||
*
|
||||
* @param array $parameters
|
||||
*/
|
||||
public function setParameters($parameters)
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the registerPHPFunctions setting on or off.
|
||||
*
|
||||
* @param bool $flag
|
||||
*/
|
||||
public function setRegisterPHPFunctions($flag)
|
||||
{
|
||||
$this->registerPHPFunctions = $flag;
|
||||
}
|
||||
//
|
||||
// Public methods
|
||||
//
|
||||
/**
|
||||
* Apply an XSLT transform to a given XML and XSL source files
|
||||
*
|
||||
* @param string $xmlFile absolute pathname to the XML source file
|
||||
* @param string $xslFile absolute pathname to the XSL stylesheet
|
||||
*
|
||||
* @return string containing the transformed XML output, or false on error
|
||||
*/
|
||||
public function transformFiles($xmlFile, $xslFile)
|
||||
{
|
||||
return $this->transform($xmlFile, self::XSL_TRANSFORMER_DOCTYPE_FILE, $xslFile, self::XSL_TRANSFORMER_DOCTYPE_FILE, self::XSL_TRANSFORMER_DOCTYPE_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply an XSLT transform to a given XML and XSL strings
|
||||
*
|
||||
* @param string $xml containing source XML
|
||||
* @param string $xsl containing source XSL
|
||||
*
|
||||
* @return string containing the transformed XML output, or false on error
|
||||
*/
|
||||
public function transformStrings($xml, $xsl)
|
||||
{
|
||||
return $this->transform($xml, self::XSL_TRANSFORMER_DOCTYPE_STRING, $xsl, self::XSL_TRANSFORMER_DOCTYPE_STRING, self::XSL_TRANSFORMER_DOCTYPE_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply an XSLT transform to a given XML and XSL. Both parameters
|
||||
* can be either strings, files or DOM objects.
|
||||
*
|
||||
* @param int $xmlType
|
||||
* @param int $xslType
|
||||
* @param int $resultType self::XSL_TRANSFORMER_DOCTYPE_...
|
||||
*
|
||||
* @return mixed return type depends on the $resultType parameter and can be
|
||||
* DOMDocument or string. The method returns a boolean value of false if the
|
||||
* transformation fails for some reason.
|
||||
*/
|
||||
public function transform($xml, $xmlType, $xsl, $xslType, $resultType)
|
||||
{
|
||||
// If either XML or XSL file don't exist, then fail without trying to process XSLT
|
||||
$fileManager = new FileManager();
|
||||
if ($xmlType == self::XSL_TRANSFORMER_DOCTYPE_FILE) {
|
||||
if (!$fileManager->fileExists($xml)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ($xslType == self::XSL_TRANSFORMER_DOCTYPE_FILE) {
|
||||
if (!$fileManager->fileExists($xsl)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The result type can only be string or DOM
|
||||
assert($resultType != self::XSL_TRANSFORMER_DOCTYPE_FILE);
|
||||
|
||||
switch (self::$processor) {
|
||||
case 'External':
|
||||
return $this->_transformExternal($xml, $xmlType, $xsl, $xslType, $resultType);
|
||||
|
||||
case 'PHP':
|
||||
return $this->_transformPHP($xml, $xmlType, $xsl, $xslType, $resultType);
|
||||
|
||||
default:
|
||||
// No XSLT processor available
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Private helper methods
|
||||
//
|
||||
/**
|
||||
* Use external programs to do the XSL transformation
|
||||
*
|
||||
* @param int $xmlType
|
||||
* @param int $xslType
|
||||
* @param int $resultType self::XSL_TRANSFORMER_DOCTYPE_...
|
||||
*
|
||||
* @return mixed return type depends on the $resultType parameter and can be
|
||||
* DOMDocument or string. Returns boolean "false" on error.
|
||||
*/
|
||||
public function _transformExternal($xml, $xmlType, $xsl, $xslType, $resultType)
|
||||
{
|
||||
// External transformation can only be done on files
|
||||
if ($xmlType != self::XSL_TRANSFORMER_DOCTYPE_FILE || $xslType != self::XSL_TRANSFORMER_DOCTYPE_FILE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check the external command to check for %xsl and %xml parameter substitution
|
||||
if (strpos(self::$externalCommand, '%xsl') === false) {
|
||||
return false;
|
||||
}
|
||||
if (strpos(self::$externalCommand, '%xml') === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assemble the parameters to be supplied to the stylesheet
|
||||
$parameterString = '';
|
||||
foreach ($this->parameters as $name => $value) {
|
||||
$parameterString .= str_replace(['%n', '%v'], [$name, $value], self::$externalParameterSnippet);
|
||||
}
|
||||
|
||||
// perform %xsl and %xml replacements for fully-qualified shell command
|
||||
$xsltCommand = str_replace(['%xsl', '%xml', '%params'], [$xsl, $xml, $parameterString], self::$externalCommand);
|
||||
|
||||
// check for safe mode and escape the shell command
|
||||
if (!ini_get('safe_mode')) {
|
||||
$xsltCommand = escapeshellcmd($xsltCommand);
|
||||
}
|
||||
|
||||
// run the shell command and get the results
|
||||
exec($xsltCommand . ' 2>&1', $contents, $status);
|
||||
|
||||
// if there is an error state, copy result to error property
|
||||
if ($status != false) {
|
||||
if ($contents) {
|
||||
$this->addError(implode("\n", $contents));
|
||||
}
|
||||
// completed with errors
|
||||
return false;
|
||||
}
|
||||
|
||||
$resultXML = implode("\n", $contents);
|
||||
|
||||
switch ($resultType) {
|
||||
case self::XSL_TRANSFORMER_DOCTYPE_STRING:
|
||||
// Directly return the XML string
|
||||
return $resultXML;
|
||||
|
||||
case self::XSL_TRANSFORMER_DOCTYPE_DOM:
|
||||
// Instantiate and configure the result DOM
|
||||
$resultDOM = new DOMDocument('1.0', static::XSLT_PROCESSOR_ENCODING);
|
||||
$resultDOM->recover = true;
|
||||
$resultDOM->substituteEntities = true;
|
||||
$resultDOM->resolveExternals = true;
|
||||
|
||||
// Load the XML and return the DOM
|
||||
$resultDOM->loadXML($resultXML);
|
||||
return $resultDOM;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use DOMDocument and XSLTProcessor to do the transformation
|
||||
*
|
||||
* @param int $xmlType
|
||||
* @param int $xslType
|
||||
* @param int $resultType self::XSL_TRANSFORMER_DOCTYPE_...
|
||||
*
|
||||
* @return mixed return type depends on the $resultType parameter and can be
|
||||
* DOMDocument or string. Returns boolean "false" on error.
|
||||
*/
|
||||
public function _transformPHP($xml, $xmlType, $xsl, $xslType, $resultType)
|
||||
{
|
||||
// Prepare the XML DOM
|
||||
if ($xmlType == self::XSL_TRANSFORMER_DOCTYPE_DOM) {
|
||||
// We already have a DOM document, no need to create one
|
||||
assert($xml instanceof DOMDocument);
|
||||
$xmlDOM = $xml;
|
||||
} else {
|
||||
// Instantiate and configure the XML DOM document
|
||||
$xmlDOM = new DOMDocument('1.0', static::XSLT_PROCESSOR_ENCODING);
|
||||
|
||||
// These are required for external entity resolution (eg. ), but can slow processing
|
||||
// substantially (20-100x), often up to 60s. This can be solved by use of local catalogs, ie.
|
||||
// putenv("XML_CATALOG_FILES=/path/to/catalog.ent");
|
||||
//
|
||||
// see: http://www.whump.com/moreLikeThis/link/03815
|
||||
$xmlDOM->recover = true;
|
||||
$xmlDOM->substituteEntities = true;
|
||||
$xmlDOM->resolveExternals = true;
|
||||
|
||||
// Load the XML based on its type
|
||||
switch ($xmlType) {
|
||||
case self::XSL_TRANSFORMER_DOCTYPE_FILE:
|
||||
$xmlDOM->load($xml);
|
||||
break;
|
||||
|
||||
case self::XSL_TRANSFORMER_DOCTYPE_STRING:
|
||||
$xmlDOM->loadXML($xml);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the XSL DOM
|
||||
if ($xslType == self::XSL_TRANSFORMER_DOCTYPE_DOM) {
|
||||
// We already have a DOM document, no need to create one
|
||||
assert($xsl instanceof DOMDocument);
|
||||
$xslDOM = $xsl;
|
||||
} else {
|
||||
// Instantiate the XSL DOM document
|
||||
$xslDOM = new DOMDocument('1.0', static::XSLT_PROCESSOR_ENCODING);
|
||||
|
||||
// Load the XSL based on its type
|
||||
switch ($xslType) {
|
||||
case self::XSL_TRANSFORMER_DOCTYPE_FILE:
|
||||
$xslDOM->load($xsl);
|
||||
break;
|
||||
|
||||
case self::XSL_TRANSFORMER_DOCTYPE_STRING:
|
||||
$xslDOM->loadXML($xsl);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Create and configure the XSL processor
|
||||
$processor = new XSLTProcessor();
|
||||
|
||||
// Register PHP functions if requested.
|
||||
// NB: This can open potential security issues; see FAQ/README
|
||||
if ($this->registerPHPFunctions) {
|
||||
$processor->registerPHPFunctions();
|
||||
}
|
||||
|
||||
// Set XSL parameters (if any)
|
||||
if (is_array($this->parameters)) {
|
||||
foreach ($this->parameters as $param => $value) {
|
||||
$processor->setParameter(null, $param, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// Import the style sheet
|
||||
$processor->importStylesheet($xslDOM);
|
||||
|
||||
// Process depending on the requested result type
|
||||
switch ($resultType) {
|
||||
case self::XSL_TRANSFORMER_DOCTYPE_STRING:
|
||||
$resultXML = $processor->transformToXML($xmlDOM);
|
||||
return $resultXML;
|
||||
|
||||
case self::XSL_TRANSFORMER_DOCTYPE_DOM:
|
||||
$resultDOM = $processor->transformToDoc($xmlDOM);
|
||||
return $resultDOM;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error to the current error list
|
||||
*
|
||||
* @param string $error
|
||||
*/
|
||||
public function addError($error)
|
||||
{
|
||||
array_push($this->errors, $error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\xslt\XSLTransformer', '\XSLTransformer');
|
||||
foreach (['XSL_TRANSFORMER_DOCTYPE_STRING', 'XSL_TRANSFORMER_DOCTYPE_FILE', 'XSL_TRANSFORMER_DOCTYPE_DOM'] as $constantName) {
|
||||
define($constantName, constant('\XSLTransformer::' . $constantName));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user