Location: PHPKode > projects > PHPTAL > PHPTAL-1.2.2/PHPTAL/PreFilter/Normalize.php
<?php
/**
 * PHPTAL templating engine
 *
 * PHP Version 5
 *
 * @category HTML
 * @package  PHPTAL
 * @author   Kornel Lesiński <hide@address.com>
 * @license  http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
 * @version  SVN: $Id: $
 * @link     http://phptal.org/
 */

/**
 * Collapses conscutive whitespace, trims attributes, merges adjacent text nodes
 */
class PHPTAL_PreFilter_Normalize extends PHPTAL_PreFilter
{
    function filter($src)
    {
        return str_replace("\r\n", "\n", $src);
    }

    function filterDOM(PHPTAL_Dom_Element $root)
    {
        // let xml:space=preserve preserve attributes as well
        if ($root->getAttributeNS("http://www.w3.org/XML/1998/namespace", 'space') == 'preserve') {
            $this->findElementToFilter($root);
            return;
        }

        $this->normalizeAttributes($root);

        // <pre> may have attributes normalized
        if ($this->isSpaceSensitiveInXHTML($root)) {
            $this->findElementToFilter($root);
            return;
        }

        $lastTextNode = null;
        foreach ($root->childNodes as $node) {

            // CDATA is not normalized by design
            if ($node instanceof PHPTAL_Dom_Text) {
                $norm = $this->normalizeSpace($node->getValueEscaped(), $node->getEncoding());
                $node->setValueEscaped($norm);

                if ('' === $norm) {
                    $root->removeChild($node);
                } else if ($lastTextNode) {
                    // "foo " . " bar" gives 2 spaces.
                    $norm = $lastTextNode->getValueEscaped().ltrim($norm,' ');

                    $lastTextNode->setValueEscaped($norm); // assumes all nodes use same encoding (they do)
                    $root->removeChild($node);
                } else {
                    $lastTextNode = $node;
                }
            } else {
                $lastTextNode = null;
                if ($node instanceof PHPTAL_Dom_Element) {
                    $this->filterDOM($node);
                }
            }
        }
    }

    protected function isSpaceSensitiveInXHTML(PHPTAL_Dom_Element $element)
    {
        $ln = $element->getLocalName();
        return ($ln === 'script' || $ln === 'pre' || $ln === 'textarea')
            && ($element->getNamespaceURI() === 'http://www.w3.org/1999/xhtml' || $element->getNamespaceURI() === '');
    }

    protected function findElementToFilter(PHPTAL_Dom_Element $root)
    {
        foreach ($root->childNodes as $node) {
            if (!$node instanceof PHPTAL_Dom_Element) continue;

            if ($node->getAttributeNS("http://www.w3.org/XML/1998/namespace", 'space') == 'default') {
                $this->filterDOM($node);
            }
        }
    }

    /**
     * does not trim
     */
    protected function normalizeSpace($text, $encoding)
    {
        $utf_regex_mod = ($encoding=='UTF-8'?'u':'');

        return preg_replace('/\s+/'.$utf_regex_mod, ' ', $text);
    }

    protected function normalizeAttributes(PHPTAL_Dom_Element $element)
    {
        foreach ($element->getAttributeNodes() as $attrnode) {

            // skip replaced attributes (because getValueEscaped on them is meaningless)
            if ($attrnode->getReplacedState() !== PHPTAL_Dom_Attr::NOT_REPLACED) continue;

            $val = $this->normalizeSpace($attrnode->getValueEscaped(), $attrnode->getEncoding());
            $attrnode->setValueEscaped(trim($val, ' '));
        }
    }
}
Return current item: PHPTAL