'', 'html4trans' => '', 'xhtml1strict' => '', ); function TemplateParser($db, $replacements = array()) { $this->db = $db; $this->replacements = $replacements; } function parse($data) { $this->parser = xml_parser_create(); // Set XML parser to take the case of tags in to account xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false); // Set XML parser callback functions xml_set_object($this->parser, $this); xml_set_element_handler($this->parser, 'tag_open', 'tag_close'); xml_set_character_data_handler($this->parser, 'cdata'); if (!xml_parse($this->parser, $data)) { die(sprintf('XML error: %s at line %d', xml_error_string(xml_get_error_code($this->parser)), xml_get_current_line_number($this->parser))); } xml_parser_free($this->parser); return trim($this->output); } function tag_open($parser, $tag, $attr) { $singletag = false; switch ($tag) { case 'doctype': $this->handle_doctype($attr); return; case 'include': if (!isset($attr['template'])) { die('include tag has no template attribute'); } $path = $this->templatedir.$attr['template'].'.xml'; if (!file_exists($path)) { die("Template $path does not exist"); } $temp = new TemplateParser($this->db, $attr); $this->output .= $temp->parse(implode('', file($path))); return; case 'ignore-start': $this->collect = true; // Although we have no intention of using it return; case 'ignore-stop': $this->buffer = ''; $this->collect = false; return; case 'sql': if (!isset($attr['id'])) { die('sql tag has no id attribute'); } $this->sqlid = $attr['id']; $this->collect = true; return; case 'output': if (!isset($attr['sql'])) { die('output tag has no sql attribute'); } $this->outputsql = $attr['sql']; $this->collect = true; return; case 'template': return; case 'img': // These are all HTML elements with no end tag case 'br': case 'link': case 'meta': case 'hr': $singletag = true; } // Now either collect or add the tag to output $xml = '<'.$tag.$this->makeattr($attr); if ($singletag) { $xml .= ' />'; } else { $xml .= '>'; } if ($this->collect) { $this->buffer .= $xml; } else { $this->output .= $xml; } } function tag_close($parser, $tag) { switch ($tag) { case 'sql': $this->sql[$this->sqlid] = $this->convert($this->buffer); $this->buffer = ''; $this->collect = false; return; case 'output': // This is the tricky one. Run the SQL query, loop through it // and run convert on the saved block multiple times replacing with // the results of the query // First clear the buffer $block = $this->buffer; $this->buffer = ''; $this->collect = false; // Now run the query $sql = $this->sql[$this->outputsql]; $result = mysql_query($sql, $this->db); if (!$result) { die("SQL query failed: '$sql'"); } $i = 0; while ($row = mysql_fetch_assoc($result)) { $row['#'] = ++$i; // '%#%' is now available as a counter var $this->output .= $this->convert($block, $row); } return; case 'template': // These are template elements with no end tag case 'include': case 'ignore-start': case 'ignore-stop': case 'doctype': case 'img': // These are all HTML elements with no end tag case 'br': case 'link': case 'meta': case 'hr': return; } // Add the end tag to the buffer or output $xml = ''; if ($this->collect) { $this->buffer .= $xml; } else { $this->output .= $xml; } } function cdata($parser, $data) { if ($this->collect) { $this->buffer .= $data; return; } $this->output .= $this->convert($data); } function convert($text, $replacements = false) { if (!$replacements) { $replacements = $this->replacements; } if (strpos($text, '%') === false) { return $text; // Nothing to replace } foreach ($replacements as $from => $to) { $text = str_replace('%'.$from.'%', $to, $text); } return $text; } function makeattr($attr) { $return = ''; foreach ($attr as $name => $value) { $return .= $name.'="'.$value.'"'; } if ($return != '') { $return = ' '.$return; } return $return; } function handle_doctype($attr) { if (!isset($attr['type'])) { die('doctype requires type attribute'); } if (!in_array($attr['type'], array_keys($this->doctypes))) { die('doctype requires valid type attribute'); } $this->output .= $this->doctypes[$attr['type']]; } } ?>