node * @return void */ public function normalize(DOMElement $template) { $this->ownerDocument = $template->ownerDocument; $this->xpath = new DOMXPath($this->ownerDocument); $this->xpath->registerNamespace('xsl', self::XMLNS_XSL); foreach ($this->getNodes() as $node) { $this->normalizeNode($node); } $this->reset(); } /** * Create an element in current template * * @param string $nodeName * @param string $textContent * @return DOMElement */ protected function createElement($nodeName, $textContent = '') { $methodName = 'createElement'; $args = [$nodeName]; // Add the text content for the new element if ($textContent !== '') { $args[] = htmlspecialchars($textContent, ENT_NOQUOTES, 'UTF-8'); } // Handle namespaced elements $prefix = strstr($nodeName, ':', true); if ($prefix > '') { $methodName .= 'NS'; array_unshift($args, $this->ownerDocument->lookupNamespaceURI($prefix)); } return call_user_func_array([$this->ownerDocument, $methodName], $args); } /** * Create an xsl:text element or a text node in current template * * @param string $content * @return DOMNode */ protected function createText($content) { return (trim($content) === '') ? $this->createElement('xsl:text', $content) : $this->ownerDocument->createTextNode($content); } /** * Create a text node in current template * * @param string $content * @return DOMText */ protected function createTextNode($content) { return $this->ownerDocument->createTextNode($content); } /** * Query and return a list of nodes of interest * * @return DOMNode[] */ protected function getNodes() { $query = implode(' | ', $this->queries); return ($query === '') ? [] : $this->xpath($query); } /** * Test whether given node is an XSL element * * @param DOMNode $node * @param string $localName * @return bool */ protected function isXsl(DOMNode $node, $localName = null) { return ($node->namespaceURI === self::XMLNS_XSL && (!isset($localName) || $localName === $node->localName)); } /** * Make an ASCII string lowercase * * @param string $str Original string * @return string Lowercased string */ protected function lowercase($str) { return strtr($str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); } /** * Normalize given attribute * * @param DOMAttr $attribute * @return void */ protected function normalizeAttribute(DOMAttr $attribute) { } /** * Normalize given element * * @param DOMElement $element * @return void */ protected function normalizeElement(DOMElement $element) { } /** * Normalize given node * * @param DOMNode $node * @return void */ protected function normalizeNode(DOMNode $node) { if (!$node->parentNode) { // Ignore nodes that have been removed from the document return; } if ($node instanceof DOMElement) { $this->normalizeElement($node); } elseif ($node instanceof DOMAttr) { $this->normalizeAttribute($node); } } /** * Reset this instance's properties after usage * * @return void */ protected function reset() { $this->ownerDocument = null; $this->xpath = null; } /** * Evaluate given XPath expression * * For convenience, $XSL is replaced with the XSL namespace URI as a string * * @param string $query XPath query * @param DOMNode $node Context node * @return DOMNode[] */ protected function xpath($query, DOMNode $node = null) { $query = str_replace('$XSL', '"' . self::XMLNS_XSL . '"', $query); return iterator_to_array($this->xpath->query($query, $node)); } }