codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
<?php /** * Exception class for the XMLDocument class. */ class XMLDocumentException extends Exception { } /** * A simple stack-based XML string constructor for creating XML. * @author Peter Goodman */ class XMLDocument { const TAG_CLOSING = 1, TAG_NON_CLOSING = 0; private $tags = array(), $indent = -1; /** * Construct the class and put in the base <xml> tag. This tag is non- * removable from the stack and isn't built in the usual way :) It's an * exception to the rule. */ public function __construct() { $this->push(' '); $xml =& $this->tags[$this->indent]; $xml['children'] = -1; $xml['content'] = '<?xml version="1.0"?>'; $this->indent = -1; } // destructor, obvious. public function __destruct() { unset($this->stack); } /** * Add some content to the current tag on the top of the stack. */ public function hasContent($content = "") { $tag =& $this->tags[$this->indent+1]; // wrap the content in a CDATA block if it contains tags if(preg_match("~[\<\>]~i", $content)) $content = "<![CDATA[\n{$content}\n]]>"; // what should the indent prefix be? $prefix = $this->indent > 0 ? str_repeat("\t", $this->indent) : ''; // prefix the content $c = ""; foreach(explode("\n", $content) as $line) { if(strlen($line) > 0) { $tag['content_num_lines']++; $c .= $prefix . $line; } } // only one line, lets remove the prefix if($tag['content_num_lines'] == 1) $c = substr($c, strlen($prefix)); $tag['content'] .= $c; return $this; } /** * Push a tag onto the XML tag stack. */ public function push($name = '', $type = TAG_CLOSING) { // we can't push no tag onto the tag stack if(empty($name) || !is_string($name)) throw new XMLDocumentException("Tag name expected in push operation."); $this->indent++; $this->tags[] = array('name' => $name, 'closing' => (bool)$type, 'attr' => '', 'content' => '', 'children' => 0, 'content_num_lines' => 0); // get the parent tag and tell it that it has one more child. The // children is also incremented in the pop method; however, these // don't conflict because the lowest level child will have 0 children // and this will have already been called. Thus, 1 + 0 accurately // represents the number of children the node at the top of the stack // has when a leaf node is popped, and so it all bubbles up nicely. $parent =& $this->tags[$this->indent]; $parent['children']++; return $this; } /** * Pop the current tag off of the tag stack. */ public function pop($expect = NULL) { // we've closed all tags, this is a guard against popping the xml // tag off the stack if($this->indent < 0) throw new XMLDocumentException("No tags left to close."); $tag =& array_pop($this->tags); // did we expect to close a certain tag name and it's not the same one // that the class expects? if($expect !== NULL && $tag['name'] != $expect) throw new XMLDocumentException("Malformed XML. Expected [{$expect}] " ."but found [{$tag['name']}]."); // this builds the output from the inside out by putting the content // into the parent tag's content. $prefix = $this->indent > 0 ? str_repeat("\t", $this->indent) : ''; $suffix = !$tag['closing'] ? ' /' : ''; $content = "\n{$prefix}<". $tag['name'] . $tag['attr'] . $suffix .">"; // do we need to build the contents of this tag? if($tag['closing']) { // write this tag over multiple lines if($tag['content_num_lines'] > 1 || $tag['children'] > 0) $content .= "{$prefix}". $tag['content'] ."\n{$prefix}"; // write this tag over a single line else $content .= $tag['content']; $content .= '</'. $tag['name'] .">"; } // add stuff into the parent and modify its content and children // counter $parent =& $this->tags[$this->indent]; $parent['content'] .= $content; $parent['children'] += $tag['children']; $this->indent--; return $this; } /** * Append an attribute to the top tag in the stack. This is really just a * convenient shortcut. */ public function __call($attr, array $args) { if(empty($attr)) throw new XMLDocumentException("XML tag attribute must has a name."); $tag =& $this->tags[$this->indent+1]; $tag['attr'] .= " {$attr}=\"". preg_replace('~"~', '\"', (string)$args[0]) ."\""; return $this; } /** * Secondary function for attributes if an attribute, for example, has a * colon in its name or has the name push, pop, or one of the other names * of one of this class' functions. */ public function hasAttribute($name = '', $val = '') { return $this->__call((string)$name, array((string)$val)); } /** * Do the header call. */ public function doHeader() { header("Content-Type: text/xml"); } /** * Return the built XML string. */ public function __toString() { // whoops, we're not done building the xml document yet! if($this->indent > 0) throw new XMLDocumentException("Cannot export malformed XML document."); return (string)$this->tags[0]['content']; } } $xml = new XMLDocument; $xml->push('rss')->version("2.0")->encoding("UTF-8") ->push('channel') ->push('title')->hasContent("Feed title here")->pop() ->push('pubDate')->hasContent(date("D, d M Y H:i:s O"))->pop() ->push('link')->hasContent("http://ioreader.com")->pop() ->push('language')->hasContent("en-us")->pop(); // create the xml for each item $xml->push('item') ->push('title')->hasContent("hello world")->pop() ->push('link')->hasContent("http://ioreader.com")->pop() ->push('description')->hasContent("this is a description")->pop() ->push('pubDate')->hasContent(date("D, d M Y H:i:s O"))->pop() ->push('guid')->hasContent(12345)->isPermaLink("false")->pop() ->pop('item'); // close remaining tags and output the xml $xml->pop('channel')->pop('rss'); echo $xml;
Private
[
?
]
Run code