forked from s9e/TextFormatter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TemplateChecks: added DisallowUnsupportedXSL, enabled by default
- Loading branch information
Showing
6 changed files
with
489 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
src/Configurator/TemplateChecks/AbstractXSLSupportCheck.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
<?php declare(strict_types=1); | ||
|
||
/** | ||
* @package s9e\TextFormatter | ||
* @copyright Copyright (c) 2010-2020 The s9e authors | ||
* @license http://www.opensource.org/licenses/mit-license.php The MIT License | ||
*/ | ||
namespace s9e\TextFormatter\Configurator\TemplateChecks; | ||
|
||
use DOMElement; | ||
use DOMXPath; | ||
use RuntimeException; | ||
use s9e\TextFormatter\Configurator\Helpers\AVTHelper; | ||
use s9e\TextFormatter\Configurator\Items\Tag; | ||
use s9e\TextFormatter\Configurator\TemplateCheck; | ||
|
||
abstract class AbstractXSLSupportCheck extends TemplateCheck | ||
{ | ||
/** | ||
* @var string[] List of supported XSL elements (local name only) | ||
*/ | ||
protected $supportedElements = []; | ||
|
||
/** | ||
* @var string[] List of supported XPath functions | ||
*/ | ||
protected $supportedFunctions = []; | ||
|
||
/** | ||
* @var string[] List of supported XPath operators | ||
*/ | ||
protected $supportedOperators = ['and', 'div', 'mod', 'or']; | ||
|
||
/** | ||
* Check for elements not supported by the PHP renderer | ||
* | ||
* @param DOMElement $template <xsl:template/> node | ||
* @param Tag $tag Tag this template belongs to | ||
*/ | ||
public function check(DOMElement $template, Tag $tag): void | ||
{ | ||
$this->checkXslElements($template); | ||
$this->checkXPathExpressions($template); | ||
} | ||
|
||
/** | ||
* Check given XPath expression | ||
*/ | ||
protected function checkXPathExpression(string $expr): void | ||
{ | ||
preg_match_all('("[^"]*+"|\'[^\']*+\'|((?:[a-z]++-)*+[a-z]++)(?=\\s*\\())', $expr, $m); | ||
foreach (array_filter($m[1]) as $funcName) | ||
{ | ||
if (!in_array($funcName, $this->supportedFunctions, true) | ||
&& !in_array($funcName, $this->supportedOperators, true)) | ||
{ | ||
throw new RuntimeException('XPath function ' . $funcName . '() is not supported'); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Check all XPath expressions in given template | ||
*/ | ||
protected function checkXPathExpressions(DOMElement $template): void | ||
{ | ||
foreach ($this->getXPathExpressions($template) as $expr) | ||
{ | ||
$this->checkXPathExpression($expr); | ||
} | ||
} | ||
|
||
/** | ||
* Check all XSL elements in given template | ||
*/ | ||
protected function checkXslElements(DOMElement $template): void | ||
{ | ||
$xpath = new DOMXPath($template->ownerDocument); | ||
$nodes = $xpath->query('/xsl:template//xsl:*'); | ||
foreach ($nodes as $node) | ||
{ | ||
if (!in_array($node->localName, $this->supportedElements, true)) | ||
{ | ||
throw new RuntimeException('xsl:' . $node->localName . ' elements are not supported'); | ||
} | ||
|
||
$methodName = 'checkXsl' . str_replace(' ', '', ucwords(str_replace('-', ' ', $node->localName))) . 'Element'; | ||
if (method_exists($this, $methodName)) | ||
{ | ||
$this->$methodName($node); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Return all XPath expressions in given template | ||
*/ | ||
protected function getXPathExpressions(DOMElement $template): array | ||
{ | ||
$exprs = []; | ||
$xpath = new DOMXPath($template->ownerDocument); | ||
|
||
$query = '//xsl:*/@name | //*[namespace-uri() != "' . self::XMLNS_XSL . '"]/@*[contains(., "{")]'; | ||
foreach ($xpath->query($query) as $attribute) | ||
{ | ||
foreach (AVTHelper::parse($attribute->value) as [$type, $content]) | ||
{ | ||
if ($type === 'expression') | ||
{ | ||
$exprs[] = $content; | ||
} | ||
} | ||
} | ||
|
||
$query = '//xsl:*/@select | //xsl:*/@test'; | ||
foreach ($xpath->query($query) as $attribute) | ||
{ | ||
$exprs[] = $attribute->value; | ||
} | ||
|
||
return $exprs; | ||
} | ||
} |
66 changes: 66 additions & 0 deletions
66
src/Configurator/TemplateChecks/DisallowUnsupportedXSL.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
<?php declare(strict_types=1); | ||
|
||
/** | ||
* @package s9e\TextFormatter | ||
* @copyright Copyright (c) 2010-2020 The s9e authors | ||
* @license http://www.opensource.org/licenses/mit-license.php The MIT License | ||
*/ | ||
namespace s9e\TextFormatter\Configurator\TemplateChecks; | ||
|
||
use DOMElement; | ||
use RuntimeException; | ||
|
||
class DisallowUnsupportedXSL extends AbstractXSLSupportCheck | ||
{ | ||
protected $supportedElements = ['apply-templates', 'attribute', 'choose', 'comment', 'copy-of', 'element', 'for-each', 'if', 'number', 'otherwise', 'processing-instruction', 'sort', 'text', 'value-of', 'variable', 'when']; | ||
|
||
protected $supportedFunctions = ['boolean', 'ceiling', 'concat', 'contains', 'count', 'current', 'document', 'element-available', 'false', 'floor', 'format-number', 'function-available', 'generate-id', 'id', 'key', 'lang', 'last', 'local-name', 'name', 'namespace-uri', 'normalize-space', 'not', 'number', 'position', 'round', 'starts-with', 'string', 'string-length', 'substring', 'substring-after', 'substring-before', 'sum', 'system-property', 'translate', 'true', 'unparsed-entity-uri']; | ||
|
||
protected function checkXslApplyTemplatesElement(DOMElement $applyTemplates): void | ||
{ | ||
if ($applyTemplates->hasAttribute('mode')) | ||
{ | ||
throw new RuntimeException('xsl:apply-templates elements do not support the mode attribute'); | ||
} | ||
} | ||
|
||
protected function checkXslCopyOfElement(DOMElement $copyOf): void | ||
{ | ||
if (!$copyOf->hasAttribute('select')) | ||
{ | ||
throw new RuntimeException('xsl:copy-of elements require a select attribute'); | ||
} | ||
} | ||
|
||
protected function checkXslIfElement(DOMElement $if): void | ||
{ | ||
if (!$if->hasAttribute('test')) | ||
{ | ||
throw new RuntimeException('xsl:if elements require a test attribute'); | ||
} | ||
} | ||
|
||
protected function checkXslValueOfElement(DOMElement $valueOf): void | ||
{ | ||
if (!$valueOf->hasAttribute('select')) | ||
{ | ||
throw new RuntimeException('xsl:value-of elements require a select attribute'); | ||
} | ||
} | ||
|
||
protected function checkXslVariableElement(DOMElement $variable): void | ||
{ | ||
if (!$variable->hasAttribute('name')) | ||
{ | ||
throw new RuntimeException('xsl:variable elements require a name attribute'); | ||
} | ||
} | ||
|
||
protected function checkXslWhenElement(DOMElement $when): void | ||
{ | ||
if (!$when->hasAttribute('test')) | ||
{ | ||
throw new RuntimeException('xsl:when elements require a test attribute'); | ||
} | ||
} | ||
} |
Oops, something went wrong.