1 <?php rcs_id('$Id: RssWriter.php,v 1.1 2001-12-07 22:15:43 dairiki Exp $');
3 * Code for creating RSS 1.0.
6 // FIXME: this should probably be improved/cleaned then moved into its own file.
13 function XmlElement ($name, $attr = false, $content = false) {
15 $this->_attr = array();
16 if (is_array($attr)) {
19 $this->_content = array();
25 function set ($attr, $value = false) {
26 if (is_array($attr)) {
27 assert($value === false);
28 foreach ($attr as $a => $v)
32 assert(is_string($attr));
33 assert(is_string($value));
34 $this->_attr[$attr] = $value;
38 function get ($attr) {
39 if (isset($this->_attr[$attr]))
40 return $this->_attr[$attr];
45 function add ($content) {
46 if (!is_array($content))
47 $content = array($content);
48 foreach ($content as $c)
49 $this->_content[] = $c;
52 function asString ($indent = '') {
53 $begin[0] = $indent . '<' . $this->_name;
54 $nchars = strlen($begin[0]) + 1;
57 while (list ($attr, $value) = each($this->_attr)) {
58 $q = sprintf('%s="%s"',
59 $attr, $this->_quote_attribute($value));
60 $nchars += strlen($q) + 1;
65 $xml = join("\n$indent ", $begin);
68 $xml = join(" ", $begin);
71 if (($n = count($this->_content)) > 0) {
74 $c = $this->_content[0];
76 $xml .= "\n" . $c->asString($indent . " ");
80 $xml .= $this->_quote($c);
84 for ($i = 1; $i < $n; $i++) {
85 $c = $this->_content[$i];
87 $xml .= "\n$indent" . $this->_quote($c);
90 $xml .= "\n" . $c->asString($indent . " ");
97 $xml .= sprintf("</%s>", $this->_name);
105 function _quote ($string) {
106 return str_replace('<', '<',
107 str_replace('>', '>',
108 str_replace('&', '&', $string)));
111 function _quote_attribute ($value) {
112 return str_replace('"', '"', $this->_quote($value));
119 * A class for writing RSS 1.0.
121 * @see http://purl.org/rss/1.0/spec,
122 * http://www.usemod.com/cgi-bin/mb.pl?ModWiki
124 class RssWriter extends XmlElement
126 function RssWriter () {
127 $this->XmlElement('rdf:RDF',
128 array('xmlns' => "http://purl.org/rss/1.0/",
129 'xmlns:rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'));
131 $this->_modules = array(
133 'content' => "http://purl.org/rss/1.0/modules/content/",
134 'dc' => "http://purl.org/dc/elements/1.1/",
135 'sy' => "http://purl.org/rss/1.0/modules/syndication/",
137 'wiki' => "http://purl.org/rss/1.0/modules/wiki/",
138 'ag' => "http://purl.org/rss/1.0/modules/aggregation/",
139 'annotate' => "http://purl.org/rss/1.0/modules/annotate/",
140 'audio' => "http://media.tangent.org/rss/1.0/",
141 'cp' => "http://my.theinfo.org/changed/1.0/rss/",
142 'rss091' => "http://purl.org/rss/1.0/modules/rss091/",
143 'slash' => "http://purl.org/rss/1.0/modules/slash/",
144 'taxo' => "http://purl.org/rss/1.0/modules/taxonomy/",
145 'thr' => "http://purl.org/rss/1.0/modules/threading/"
148 $this->_uris_seen = array();
149 $this->_items = array();
152 function registerModule($alias, $uri) {
153 assert(!isset($this->_modules[$alias]));
154 $this->_modules[$alias] = $uri;
157 // Args should include:
158 // 'title', 'link', 'description'
161 function channel($properties, $uri = false) {
162 $this->_channel = $this->__node('channel', $properties, $uri);
165 // Args should include:
168 // 'description', 'URI'
169 function addItem($properties, $uri = false) {
170 $this->_items[] = $this->__node('item', $properties, $uri);
173 // Args should include:
174 // 'url', 'title', 'link'
177 function image($properties, $uri = false) {
178 $this->_image = $this->__node('image', $properties, $uri);
182 // Args should include:
183 // 'title', 'description', 'name', and 'link'
186 function textinput($properties, $uri = false) {
187 $this->_textinput = $this->__node('textinput', $properties, $uri);
191 * Finish construction of RSS.
194 if (isset($this->_finished))
197 $channel = &$this->_channel;
198 $items = &$this->_items;
201 $seq = new XmlElement('rdf:Seq');
202 foreach ($items as $item)
203 $seq->add($this->__ref('rdf:li', $item));
204 $channel->add(new XmlElement('items', false, $seq));
207 if (isset($this->_image)) {
208 $channel->add($this->__ref('image', $this->_image));
209 $items[] = $this->_image;
211 if (isset($this->_textinput)) {
212 $channel->add($this->__ref('textinput', $this->_textinput));
213 $items[] = $this->_textinput;
216 $this->add($channel);
220 $this->_finished = true;
224 * Get XML representation of RSS.
228 return $this->asString();
232 * Create a new RDF <i>typedNode</i>.
234 function __node($type, $properties, $uri = false) {
236 $uri = $properties['link'];
237 $attr['rdf:about'] = $this->__uniquify_uri($uri);
238 return new XmlElement($type, $attr,
239 $this->__elementize($properties));
243 * Check object URI for uniqueness, create a unique URI if needed.
245 function __uniquify_uri ($uri) {
246 if (!$uri || isset($this->_uris_seen[$uri])) {
247 $n = count($this->_uris_seen);
248 $uri = $this->_channel->get('rdf:about') . "#uri$n";
249 assert(!isset($this->_uris_seen[$uri]));
251 $this->_uris_seen[$uri] = true;
256 * Convert hash of RDF properties to <i>propertyElt</i>s.
258 function __elementize ($elements) {
260 foreach ($elements as $prop => $val) {
261 $this->__check_predicate($prop);
262 $out[] = new XmlElement($prop, false, $val);
268 * Check property predicates for XMLNS sanity.
270 function __check_predicate ($name) {
271 if (preg_match('/^([^:]+):[^:]/', $name, $m)) {
273 if (! $this->get("xmlns:$ns")) {
274 if (!isset($this->_modules[$ns]))
275 die("$name: unknown namespace ($ns)");
276 $this->set("xmlns:$ns", $this->_modules[$ns]);
282 * Create a <i>propertyElt</i> which references another node in the RSS.
284 function __ref($predicate, $reference) {
285 $attr['rdf:resource'] = $reference->get('rdf:about');
286 return new XmlElement($predicate, $attr);
291 // (c-file-style: "gnu")
296 // c-hanging-comment-ender-p: nil
297 // indent-tabs-mode: nil