<?php #-*-Mode: php; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/*
xml_detail_parser for PHP 4.
Copyright (C) 2004 John J Foerch
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* The xml_detail_parser class facilitates working with xml raw
data. This class creates two data trees similar in structure to
those produced by xml_parse_into_struct. Additionally, each
node of the tree has an element called position, which contains
its byte position in the raw data. This information can be used
to better handle CDATA.
*/
class xml_detail_parser {
var $ok=true;
var $error;
var $level=0;
var $current_index = 0;
var $struct = array();
var $index = array();
var $tag_indices = array();
var $content='';
var $current_tag_is_complete=false;
var $fulltags = false;
var $ignore_tags = false;
var $supported_tags;
var $ignore_level = false;//used when ignoring tags
function xml_detail_parser (&$xmldata) {
$this->content = $xmldata;
if (func_num_args () > 1)
{
$ops = func_get_arg (1);
$this->options ($ops);
}
$parser = xml_parser_create();
xml_set_object ($parser, $this);
xml_set_element_handler ($parser,'start_element','end_element');
$parse_success = xml_parse ($parser,$this->content,true);
if ($parse_success === false)
{
$this->ok = false;
$this->error = xml_error_string(xml_get_error_code($parser));
}
xml_parser_free ($parser);
}
function options (&$ops) {
if (isset ($ops['fulltags']) && $ops['fulltags'] === true)
$this->fulltags = true;
if (isset ($ops['support']))
{
$this->ignore_tags = true;
$this->supported_tags = explode (',', $ops['support']);
}
}
function start_element (&$parser, $name, &$attr) {
++$this->level;
$position = xml_get_current_byte_index ($parser);
$fulltag = substr ($this->content, $position);
$fulltag = substr ($fulltag, 0, strpos ($fulltag,'>')+1);
$type = $fulltag[strlen ($fulltag) - 2] == '/' ? 'complete' : 'open';
if ($type == 'complete') $this->current_tag_is_complete = true;
if ($this->ignore_tags == true)
{
if ($this->ignore_level == false &&
in_array ($name, $this->supported_tags) == false)
{
$this->ignore_level = $this->level;
}
}
if ($this->ignore_tags == false || $this->ignore_level == false)
{
$this->struct[$this->current_index] = array (
'tag' => $name,
'type' => $type,
'level' => $this->level,
'position' => $position,
'taglen' => strlen ($fulltag)
);
if ($this->fulltags)
{
$this->struct[$this->current_index]['fulltag'] = $fulltag;
}
if (count ($attr) > 0)
{
$this->struct[$this->current_index]['attributes'] = $attr;
}
$this->tag_indices[] = $this->current_index;
if (! isset ($this->index[$name])) $this->index[$name] = array();
$this->index[$name][] = $this->current_index;
++$this->current_index;
}
}
function end_element (&$parser, $name) {
if ($this->ignore_level == false)
$open_index = array_pop ($this->tag_indices);
if ($this->current_tag_is_complete)
{
$this->current_tag_is_complete = false;
--$this->level;
if ($this->level == $this->ignore_level)
$this->ignore_level = false;
return;
}
if ($this->ignore_level == false)
{
$position = xml_get_current_byte_index ($parser);
$this->struct[$this->current_index] = array (
'tag' => $name,
'type' => 'close',
'level' => $this->level,
'open' => $open_index,
'position' => $position
);
$this->struct[$open_index]['close'] = $this->current_index;
if (! isset ($this->index[$name])) $this->index[$name] = array();
$this->index[$name][] = $this->current_index;
++$this->current_index;
}
if ($this->level == $this->ignore_level) $this->ignore_level = false;
--$this->level;
}
function cdata_for_tag (&$tag) {
$clip_start = $tag['position'] + $tag['taglen'];
$clip_end = $this->struct[$tag['close']]['position'];
$clip_length = $clip_end - $clip_start;
return substr ($this->content, $clip_start, $clip_length);
}
}
?>