s9e/sweetdom

专注于XSLT 1.0模板操作的DOM API语法糖。

3.4.1 2024-03-23 14:03 UTC

README

s9e\SweetDOM是一个库,它扩展了PHP的DOM扩展,使DOM操作更简单,特别关注XSLT 1.0模板。它为最常用的DOM操作添加了语法糖,提高了跨PHP版本的兼容性,并实现了某些新方法的polyfills。

Code Coverage Scrutinizer Code Quality

安装

composer require s9e/sweetdom

API

s9e\SweetDOM\Document

s9e\SweetDOM\Document类扩展了DOMDocument,并提供了快速访问DOMXPath的evaluatequery方法。`firstOf`方法评估XPath查询并返回列表中的第一个节点,如果列表为空,则返回`null`。

mixed       evaluate(string $expression, ?DOMNode $contextNode = null, bool $registerNodeNS = true)
?DOMNode    firstOf(string $expression, ?DOMNode $contextNode = null, bool $registerNodeNS = true)
DOMNodeList query(string $expression, ?DOMNode $contextNode = null, bool $registerNodeNS = true)

s9e\SweetDOM\Document类有一个`$nodeCreator`属性,它提供了一组方法来创建元素,特别关注模板中常用的XSL元素。有关完整内容,请参阅s9e\SweetDOM\NodeCreator

Comment createComment(string $data)
Element createElement(string $nodeName, string $textContent = '')
Element createElementNS(?string $namespace, string $nodeName, string $textContent = '')
Element createXslApplyTemplates(string $select = null, string $mode = null)
Element createXslAttribute(string $name, string $textContent = '', string $namespace = null)
Element createXslChoose()
Element createXslComment(string $textContent = '')
Element createXslCopyOf(string $select)
Element createXslElement(string $name, string $namespace = null, string $useAttributeSets = null)
Element createXslIf(string $test, string $textContent = '')
Element createXslOtherwise(string $textContent = '')
Element createXslText(string $textContent = '', string $disableOutputEscaping = null)
Element createXslValueOf(string $select, string $disableOutputEscaping = null)
Element createXslVariable(string $name, string $select = null)
Element createXslWhen(string $test, string $textContent = '')

s9e\SweetDOM\Element

s9e\SweetDOM\Element类扩展了DOMElement,并提供了同时创建节点并将其相对于元素插入的一组魔法方法。对于来自s9e\SweetDOM\NodeCreator类的每个方法,在s9e\SweetDOM\Element上存在五个相应的方法。

例如,来自s9e\SweetDOM\NodeCreator的`createXslText`方法在s9e\SweetDOM\Element中变为`afterXslText`、`appendXslText`、`beforeXslText`、`prependXslText`和`replaceWithXslText`方法。每个方法都创建一个节点,执行DOM操作,然后返回该节点。以下示例说明了每个`xsl:text`元素相对于创建它们的`span`元素的位置插入,然后替换`br`元素。

$xsl = '<xsl:template xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <p><span><br/></span></p>
</xsl:template>';

$dom                     = new s9e\SweetDOM\Document;
$dom->formatOutput       = true;
$dom->preserveWhiteSpace = false;
$dom->loadXML($xsl);

$span    = $dom->firstOf('//span');
$methods = ['afterXslText', 'appendXslText', 'beforeXslText', 'prependXslText'];
foreach ($methods as $methodName)
{
	$span->$methodName($methodName);
}
$dom->firstOf('//br')->replaceWithXslText('replaceWithXslText');
echo $dom->saveXML($dom->documentElement);
<xsl:template xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <p>
    <xsl:text>beforeXslText</xsl:text>
    <span>
      <xsl:text>prependXslText</xsl:text>
      <xsl:text>replaceWithXslText</xsl:text>
      <xsl:text>appendXslText</xsl:text>
    </span>
    <xsl:text>afterXslText</xsl:text>
  </p>
</xsl:template>

XPath方法在元素级别也可用,并使用元素本身作为上下文节点。

$dom = new s9e\SweetDOM\Document;
$dom->loadXML('<x id="1"><x id="2"/></x>');

var_dump($dom->firstOf('//x')->getAttribute('id'));
var_dump($dom->firstOf('//x')->firstOf('x')->getAttribute('id'));
string(1) "1"
string(1) "2"

可以使用以下API轻松创建和将元素相对于上下文节点添加。

Element afterElement(string $nodeName, string $textContent = '')
Element appendElement(string $nodeName, string $textContent = '')
Element beforeElement(string $nodeName, string $textContent = '')
Element prependElement(string $nodeName, string $textContent = '')
$dom                     = new s9e\SweetDOM\Document;
$dom->formatOutput       = true;
$dom->preserveWhiteSpace = false;
$dom->loadXML('<p><span><br/></span></p>');

$span    = $dom->firstOf('//span');
$methods = ['afterElement', 'appendElement', 'beforeElement', 'prependElement'];
foreach ($methods as $methodName)
{
	$span->$methodName('i', $methodName);
}
echo $dom->saveXML($dom->documentElement);
<p>
  <i>beforeElement</i>
  <span>
    <i>prependElement</i>
    <br/>
    <i>appendElement</i>
  </span>
  <i>afterElement</i>
</p>

文档片段可用于批量操作或在DOM中插入XML。

$dom = new s9e\SweetDOM\Document;
$dom->loadXML('<x/>');

$x = $dom->firstOf('//x');
$x->appendDocumentFragment(
	// The callback will be executed before the fragment is appended
	fn($fragment) => $fragment->appendXML('<y/><z/>')
);

echo $dom->saveXML($x);
<x><y/><z/></x>

其他扩展节点

以下DOM节点自动扩展并增加了XPath方法以及节点类型支持的任何魔法方法,通常通过DOMChildNodeDOMParentNode接口实现。

  • s9e\SweetDOM\Attr扩展了DOMAttr
  • s9e\SweetDOM\CdataSection扩展了DOMCdataSection
  • s9e\SweetDOM\Comment扩展了DOMComment
  • s9e\SweetDOM\DocumentFragment扩展了DOMDocumentFragment
  • s9e\SweetDOM\Element扩展了DOMElement
  • s9e\SweetDOM\Text扩展了DOMText

与较旧和未来的PHP版本的前后兼容性

为了提高与较旧版本的PHP以及PHP的未来的版本的兼容性,此库根据PHP版本使用不同的类集来实现节点类型。基本类在上面的s9e\SweetDOM命名空间中列出,并且在使用时应该只使用这些类来检查类类型。

与旧版本PHP的向后兼容性

为PHP < 8.3版本提供以下方法的polyfills

  • Node::isEqualNode
  • ParentNode::insertAdjacentElement
  • ParentNode::insertAdjacentText
  • ParentNode::replaceChildren

在PHP版本低于8.1.23,以及从8.2.0到8.2.9的版本中,以下方法被模拟

  • ChildNode::after
  • ChildNode::before
  • ChildNode::replaceWith
  • ParentNode::append
  • ParentNode::prepend

与未来版本PHP的前向兼容性

以下方法已被修改,以匹配PHP 8.3对断开连接的节点(无父节点的节点)的行为,并与DOM规范保持一致。

  • ChildNode::after
  • ChildNode::before
  • ChildNode::replaceWith