1<?php declare(strict_types=1); 2 3/** 4* @package s9e\SweetDOM 5* @copyright Copyright (c) 2019-2020 The s9e authors 6* @license http://www.opensource.org/licenses/mit-license.php The MIT License 7*/ 8namespace s9e\SweetDOM; 9 10use DOMDocument; 11use DOMNode; 12use DOMNodeList; 13use DOMXPath; 14 15class Document extends DOMDocument 16{ 17 /** 18 * @link https://www.php.net/manual/domdocument.construct.php 19 * 20 * @param string $version Version number of the document 21 * @param string $encoding Encoding of the document 22 */ 23 public function __construct(string $version = '1.0', string $encoding = 'utf-8') 24 { 25 parent::__construct($version, $encoding); 26 27 $this->registerNodeClass('DOMElement', Element::class); 28 } 29 30 /** 31 * Create and return an xsl:apply-templates element 32 * 33 * @param string $select XPath expression for the "select" attribute 34 * @return Element 35 */ 36 public function createXslApplyTemplates(string $select = null): Element 37 { 38 $element = $this->createElementXSL('apply-templates'); 39 if (isset($select)) 40 { 41 $element->setAttribute('select', $select); 42 } 43 44 return $element; 45 } 46 47 /** 48 * Create and return an xsl:attribute element 49 * 50 * @param string $name Attribute's name 51 * @param string $text Text content for the element 52 * @return Element 53 */ 54 public function createXslAttribute(string $name, string $text = ''): Element 55 { 56 $element = $this->createElementXSL('attribute', $text); 57 $element->setAttribute('name', $name); 58 59 return $element; 60 } 61 62 /** 63 * Create and return an xsl:choose element 64 * 65 * @return Element 66 */ 67 public function createXslChoose(): Element 68 { 69 return $this->createElementXSL('choose'); 70 } 71 72 /** 73 * Create and return an xsl:comment element 74 * 75 * @param string $text Text content for the comment 76 * @return Element 77 */ 78 public function createXslComment(string $text = ''): Element 79 { 80 return $this->createElementXSL('comment', $text); 81 } 82 83 /** 84 * Create and return an xsl:copy-of element 85 * 86 * @param string $select XPath expression for the "select" attribute 87 * @return Element 88 */ 89 public function createXslCopyOf(string $select): Element 90 { 91 $element = $this->createElementXSL('copy-of'); 92 $element->setAttribute('select', $select); 93 94 return $element; 95 } 96 97 /** 98 * Create and return an xsl:if element 99 * 100 * @param string $test XPath expression for the "test" attribute 101 * @param string $text Text content for the element 102 * @return Element 103 */ 104 public function createXslIf(string $test, string $text = ''): Element 105 { 106 $element = $this->createElementXSL('if', $text); 107 $element->setAttribute('test', $test); 108 109 return $element; 110 } 111 112 /** 113 * Create and return an xsl:otherwise element 114 * 115 * @param string $text Text content for the element 116 * @return Element 117 */ 118 public function createXslOtherwise(string $text = ''): Element 119 { 120 return $this->createElementXSL('otherwise', $text); 121 } 122 123 /** 124 * Create and return an xsl:text element 125 * 126 * @param string $text Text content for the element 127 * @return Element 128 */ 129 public function createXslText(string $text = ''): Element 130 { 131 return $this->createElementXSL('text', $text); 132 } 133 134 /** 135 * Create and return an xsl:value-of element 136 * 137 * @param string $select XPath expression for the "select" attribute 138 * @return Element 139 */ 140 public function createXslValueOf(string $select): Element 141 { 142 $element = $this->createElementXSL('value-of'); 143 $element->setAttribute('select', $select); 144 145 return $element; 146 } 147 148 /** 149 * Create and return an xsl:variable element 150 * 151 * @param string $name Name of the variable 152 * @param string $select XPath expression 153 * @return Element 154 */ 155 public function createXslVariable(string $name, string $select = null): Element 156 { 157 $element = $this->createElementXSL('variable'); 158 $element->setAttribute('name', $name); 159 if (isset($select)) 160 { 161 $element->setAttribute('select', $select); 162 } 163 164 return $element; 165 } 166 167 /** 168 * Create and return an xsl:when element 169 * 170 * @param string $test XPath expression for the "test" attribute 171 * @param string $text Text content for the element 172 * @return Element 173 */ 174 public function createXslWhen(string $test, string $text = ''): Element 175 { 176 $element = $this->createElementXSL('when', $text); 177 $element->setAttribute('test', $test); 178 179 return $element; 180 } 181 182 /** 183 * Evaluate and return the result of a given XPath expression 184 * 185 * @param string $expr XPath expression 186 * @param DOMNode $node Context node 187 * @param bool $registerNodeNS Whether to register the node's namespace 188 * @return mixed 189 */ 190 public function evaluate(string $expr, DOMNode $node = null, bool $registerNodeNS = true) 191 { 192 return $this->xpath('evaluate', func_get_args()); 193 } 194 195 /** 196 * Evaluate and return the first element of a given XPath query 197 * 198 * @param string $expr XPath expression 199 * @param DOMNode $node Context node 200 * @param bool $registerNodeNS Whether to register the node's namespace 201 * @return DOMNode|null 202 */ 203 public function firstOf(string $expr, DOMNode $node = null, bool $registerNodeNS = true): ?DOMNode 204 { 205 return $this->xpath('query', func_get_args())->item(0); 206 } 207 208 /** 209 * Evaluate and return the result of a given XPath query 210 * 211 * @param string $expr XPath expression 212 * @param DOMNode $node Context node 213 * @param bool $registerNodeNS Whether to register the node's namespace 214 * @return DOMNodeList 215 */ 216 public function query(string $expr, DOMNode $node = null, bool $registerNodeNS = true): DOMNodeList 217 { 218 return $this->xpath('query', func_get_args()); 219 } 220 221 /** 222 * Create and return an XSL element 223 * 224 * @param string $name Element's local name 225 * @param string $text Text content for the element 226 * @return Element 227 */ 228 protected function createElementXSL(string $localName, string $text = ''): Element 229 { 230 return $this->createElementNS( 231 'http://www.w3.org/1999/XSL/Transform', 232 'xsl:' . $localName, 233 htmlspecialchars($text, ENT_XML1) 234 ); 235 } 236 237 /** 238 * Execute a DOMXPath method and return the result 239 * 240 * @param string $methodName 241 * @param array $args 242 * @return mixed 243 */ 244 protected function xpath(string $methodName, array $args) 245 { 246 $xpath = new DOMXPath($this); 247 $xpath->registerNamespace('xsl', 'http://www.w3.org/1999/XSL/Transform'); 248 249 return call_user_func_array([$xpath, $methodName], $args); 250 } 251}