Posted by troelskn on Wed 24 Sep 22:47
report abuse | download | new post
- <?php
- class DomQuery {
- protected $xpath;
- function __construct($document) {
- $this->xpath = new DomXPath($document instanceOf DomDocument ? $document : $document->ownerDocument);
- }
- function getFirstElementByClassname($class_name, $node = null) {
- if (!$class_name) {
- return $node;
- }
- if ($node) {
- return $this->xpath->query("descendant::*[contains(@class,'$class_name')]", $node)->item(0);
- }
- return $this->xpath->query("descendant::*[contains(@class,'$class_name')]")->item(0);
- }
- }
- class Domling {
- protected $node;
- protected $query;
- function __construct($source) {
- $this->node = $this->parse($source);
- } else {
- $this->node = $source;
- }
- $this->query = new DomQuery($this->node);
- }
- protected function parse($html) {
- $document = new DomDocument();
- $document->loadHtml("<html><body><div>" . $html . "</div></body></html>");
- return $document->getElementsByTagName("body")->item(0)->firstChild;
- }
- $document->loadHtml($html);
- return $document;
- }
- function purge() {
- foreach ($this->captures as $capture) {
- $capture->purge();
- }
- }
- function render() {
- $this->purge();
- if ($this->node instanceOf DOMElement) {
- preg_match('~<html>\s*<body>\s*<div>([\s\S]*)</div>\s*</body>\s*</html>\s*$~', $this->node->ownerDocument->saveHtml(), $matches);
- return $matches[1];
- }
- return $this->node->saveHtml();
- }
- function capture($class_name) {
- $this->captures[$class_name] = new Capture($this->query->getFirstElementByClassname($class_name));
- }
- return $this->captures[$class_name];
- }
- function sequence($item_class_name, $container_class_name) {
- $container = $this->query->getFirstElementByClassname($container_class_name);
- $this->captures[$item_class_name.":".$container_class_name] = new Sequence(
- $this->query->getFirstElementByClassname($item_class_name, $container),
- $container);
- }
- return $this->captures[$item_class_name.":".$container_class_name];
- }
- }
- class Capture extends Domling {
- protected $placeholder_node;
- function __construct(DomElement $node) {
- parent::__construct($node);
- $this->placeholder_node = $this->node->ownerDocument->createComment("placeholder");
- $this->node->parentNode->replaceChild($this->placeholder_node, $this->node);
- }
- function purge() {
- parent::purge();
- if ($this->placeholder_node->parentNode) {
- $this->placeholder_node->parentNode->removeChild($this->placeholder_node);
- }
- }
- $clone = $this->node->cloneNode(true);
- $this->placeholder_node->parentNode->insertBefore($clone, $this->placeholder_node);
- }
- foreach ($data as $id => $value) {
- $class_name = $matches[1];
- $attribute = $matches[2];
- $element = $this->query->getFirstElementByClassname($class_name, $clone);
- $element->setAttribute($attribute, $value);
- } else {
- $element = $this->query->getFirstElementByClassname($id, $clone);
- while ($element->hasChildNodes()) {
- $element->removeChild($element->firstChild);
- }
- $element->appendChild($element->ownerDocument->createTextNode($value));
- }
- }
- return $clone;
- }
- }
- class Sequence extends Capture {
- protected $container;
- protected $placeholder_container;
- function __construct(DomElement $node, DomElement $container) {
- parent::__construct($node);
- $this->container = $container;
- $this->placeholder_container = $container->ownerDocument->createComment("container");
- $this->container->parentNode->replaceChild($this->placeholder_container, $this->container);
- }
- function purge() {
- parent::purge();
- if ($this->placeholder_container->parentNode) {
- $this->placeholder_container->parentNode->removeChild($this->placeholder_container);
- }
- }
- if (!$this->container->parentNode) {
- $this->placeholder_container->parentNode->replaceChild($this->container, $this->placeholder_container);
- }
- return parent::bind($data);
- }
- }
- // simple variable binding
- $t = new Domling('<p class="hello"></p>');
- $t->capture('hello')->bind("Hello World");
- // <p class="hello">Hello World</p>
- echo "\n---\n";
- // Switching a block out
- $t = new Domling('<p>Lorem Ipsum</p><p class="message">Hidden message</p>');
- $t->capture('message');
- // <p>Lorem Ipsum</p>
- echo "\n---\n";
- // Putting it back in
- $t = new Domling('<p>Lorem Ipsum</p><p class="message">Hidden message</p>');
- $block = $t->capture('message');
- $block->bind();
- // <p>Lorem Ipsum</p>
- // <p class="message">Hidden message</p>
- echo "\n---\n";
- // And looping over a block
- $t = new Domling('<ul class="links"><li class="link"><a class="anchor" href="#">title</a></li></ul>');
- 'Sitepoint' => 'http://www.sitepoint.com',
- 'Example' => 'http://www.example.org?foo=bar&ding=dong');
- foreach ($links as $title => $link) {
- }
- // <ul class="links">
- // <li class="link"><a class="anchor" href="http://www.sitepoint.com">Sitepoint</a></li>
- // <li class="link"><a class="anchor" href="http://www.example.org?foo=bar&ding=dong">Example</a></li>
- // </ul>
- echo "\n---\n";
- // And a full sample
- $template = "
- <h1 class='title'>title</h1>
- <ul class='links'>
- <li class='link'><a class='anchor' href='#'>title</a></li>
- </ul>
- <p class='switch'>Hide this</p>
- ";
- $t = new Domling($template);
- // let's bind some data to the template
- $t->capture('title')->bind("Hello World");
- // Or we can repeat a block as a sequence
- 'Sitepoint' => 'http://www.sitepoint.com',
- 'Example' => 'http://www.example.org?foo=bar&ding=dong');
- foreach ($links as $title => $link) {
- }
- // we can even remove a block entirely
- $t->capture('switch');
- // <h1 class="title">Hello World</h1>
- // <ul class="links">
- // <li class="link"><a class="anchor" href="http://www.sitepoint.com">Sitepoint</a></li>
- // <li class="link"><a class="anchor" href="http://www.example.org?foo=bar&ding=dong">Example</a></li>
- // </ul>
- }
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.