1366 lines
32 KiB
PHP
1366 lines
32 KiB
PHP
<?php
|
|
|
|
/*
|
|
+--------------------------------------------------------------------------
|
|
| Invision Power Board 2.1.7
|
|
| =============================================
|
|
| by Matthew Mecham
|
|
| (c) 2001 - 2005 Invision Power Services, Inc.
|
|
| http://www.invisionpower.com
|
|
| =============================================
|
|
| Web: http://www.invisionboard.com
|
|
| http://www.ibresource.ru/products/invisionpowerboard/
|
|
| Time: Tuesday 18th of July 2006 05:56:00 PM
|
|
| Release: 52f408a29988b02f45b5e6f4ba5af0ae
|
|
| Licence Info: http://www.invisionboard.com/?license
|
|
| http://www.ibresource.ru/license
|
|
+---------------------------------------------------------------------------
|
|
| INVISION POWER BOARD IS NOT FREE / OPEN SOURCE!
|
|
+---------------------------------------------------------------------------
|
|
| INVISION POWER BOARD îå ñ÷ìñåôóñ âåóðìáôîùí ðòïçòáííîùí ïâåóðåþåîéåí!
|
|
| ðÒÁ×Á ÎÁ ðï ÐÒÉÎÁÄÌÅÖÁÔ Invision Power Services
|
|
| ðÒÁ×Á ÎÁ ÐÅÒÅ×ÏÄ IBResource (http://www.ibresource.ru))
|
|
+---------------------------------------------------------------------------
|
|
| > $Date: 2005-10-10 14:03:20 +0100 (Mon, 10 Oct 2005) $
|
|
| > $Revision: 22 $
|
|
| > $Author: matt $
|
|
+---------------------------------------------------------------------------
|
|
|
|
|
| > XML handling methods (KERNEL)
|
|
| > Module written by Matt Mecham
|
|
| > Date started: 25th February
|
|
|
|
|
| > Module Version Number: 1.0.0
|
|
+--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* IPS Kernel Pages: XML Creation and Extraction Functions
|
|
*
|
|
* This class contains all generic functions to handle
|
|
* the creation of XML documents and the parsing of XML documents
|
|
*
|
|
* Example Usage:
|
|
* <code>
|
|
* <productlist name="myname" version="1.0">
|
|
* <productgroup name="thisgroup">
|
|
* <product id="1.0">
|
|
* <description>This is a descrption</description>
|
|
* <title>Baked Beans</title>
|
|
* <room store="1">103</room>
|
|
* </product>
|
|
* </productgroup>
|
|
* </productlist>
|
|
*
|
|
* // Set the root tag
|
|
* $xml->xml_set_root( 'productlist', array( 'name' => 'myname', 'version' => '1.0' ) );
|
|
*
|
|
* // Add a group
|
|
* $xml->xml_add_group( 'productgroup', array( 'name' => 'thisgroup' ) );
|
|
*
|
|
* // Build entry content
|
|
* $content[] = $xml->xml_build_simple_tag( 'description', "This is a descrption" );
|
|
* $content[] = $xml->xml_build_simple_tag( 'title' , "Baked Beans" );
|
|
* $content[] = $xml->xml_build_simple_tag( 'room' , '103' , array( 'store' => 1 ) );
|
|
*
|
|
* // Build entry
|
|
* $entry[] = $xml->xml_build_entry( 'product', $content, array( 'id' => '1.0' ) );
|
|
*
|
|
* // Add to group 'productlist'
|
|
* $xml->xml_add_entry_to_group( 'productgroup', $entry );
|
|
*
|
|
* // Format..
|
|
* $xml->xml_format_document();
|
|
*
|
|
* // Get XML document
|
|
* $filecontents = $xml->xml_document;
|
|
*
|
|
* // Parse XML document
|
|
* $xml->xml_parse_document( $filecontents );
|
|
*
|
|
* // Show XML array
|
|
* print_r( $xml->xml_array );
|
|
*
|
|
* // print "Baked Beans";
|
|
* print $xml->xml_array['productlist']['productgroup']['product'][0]['title']['VALUE'];
|
|
*
|
|
* // print "1";
|
|
* print $xml->xml_array['productlist']['productgroup']['product'][0]['room']['ATTRIBUTES']['store'];
|
|
* </code>
|
|
*
|
|
* @package IPS_KERNEL
|
|
* @subpackage XMLHandling
|
|
* @author Matt Mecham
|
|
* @copyright Invision Power Services, Inc.
|
|
* @version 2.1
|
|
*/
|
|
|
|
/**
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* XML Creation and Extraction Functions
|
|
*
|
|
* Methods and functions for handling XML documents
|
|
*
|
|
* @package IPS_KERNEL
|
|
* @subpackage XMLHandling
|
|
* @author Matt Mecham
|
|
* @version 2.1
|
|
*/
|
|
class class_xml
|
|
{
|
|
/**
|
|
* XML header
|
|
*
|
|
* @var string
|
|
*/
|
|
var $header = "";
|
|
|
|
/**
|
|
* Root tag name
|
|
*
|
|
* @var string
|
|
*/
|
|
var $root_tag = '';
|
|
|
|
/**
|
|
* Root attributes
|
|
*
|
|
* @var string
|
|
*/
|
|
var $root_attributes = "";
|
|
|
|
/**
|
|
* Array of entries
|
|
*
|
|
* @var array
|
|
*/
|
|
var $entries = array();
|
|
|
|
/**
|
|
* String of compiled XML document
|
|
*
|
|
* @var string
|
|
*/
|
|
var $xml_document = "";
|
|
|
|
/**
|
|
* Work variable
|
|
*
|
|
* @var integer
|
|
*/
|
|
var $depth = 0;
|
|
|
|
/**
|
|
* Tmp doc, used during creation
|
|
*
|
|
* @var string
|
|
*/
|
|
var $tmp_doc = "";
|
|
|
|
/**
|
|
* Tag groups
|
|
*
|
|
* @var string
|
|
*/
|
|
var $groups = "";
|
|
|
|
/**
|
|
* Index numerically flag
|
|
*
|
|
* @var integer
|
|
*/
|
|
var $index_numeric = 0;
|
|
|
|
/**
|
|
* Collapse duplicate tags flag
|
|
*
|
|
* @var integer
|
|
*/
|
|
var $collapse_dups = 1;
|
|
|
|
/**
|
|
* Main XML array of parsed components
|
|
*
|
|
* @var array
|
|
*/
|
|
var $xml_array = array();
|
|
|
|
/**
|
|
* Collapse newlines in CDATA tags
|
|
*
|
|
* @var integer
|
|
*/
|
|
var $collapse_newlines = 1;
|
|
|
|
/**
|
|
* Use lite parser flag
|
|
*
|
|
* @var integer
|
|
*/
|
|
var $lite_parser = 1;
|
|
|
|
/**
|
|
* DOC type
|
|
*
|
|
* @ var string
|
|
*/
|
|
var $doc_type = 'WINDOWS-1251';
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// CONSTRUCTOR
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function class_xml()
|
|
{
|
|
//$this->header = '<?xml version="1.0" encoding="'.$this->doc_type.'"?'.'>';
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Parse an XML document into arrays
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Parse an XML document into an array of field and values
|
|
*
|
|
* @param string Raw XML Data
|
|
* @return void
|
|
*/
|
|
function xml_parse_document( $xml )
|
|
{
|
|
$i = -1;
|
|
|
|
//-----------------------------------------
|
|
// Use "lite" parser
|
|
//-----------------------------------------
|
|
|
|
if ( $this->lite_parser )
|
|
{
|
|
$lite = new xml_lite_parse();
|
|
|
|
$lite->xml_parse_it( $xml );
|
|
|
|
$this->xml_array = $this->_xml_get_children( $lite->stack, $i );
|
|
|
|
//-----------------------------------------
|
|
// Free willy..er..memory
|
|
//-----------------------------------------
|
|
|
|
$lite->garbage_collect();
|
|
}
|
|
//-----------------------------------------
|
|
// Use PHP EXPAT Parser?
|
|
//-----------------------------------------
|
|
else
|
|
{
|
|
$parser = xml_parser_create();
|
|
|
|
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
|
|
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE , 0);
|
|
xml_parse_into_struct($parser, $xml, $vals);
|
|
xml_parser_free($parser);
|
|
|
|
$this->xml_array = $this->_xml_get_children($vals, $i);
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Garbage collect
|
|
//-----------------------------------------
|
|
|
|
unset( $vals );
|
|
unset( $xml );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Format the XML document
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Parse an array into an XML document
|
|
*
|
|
* @param array Entry array
|
|
* @return void
|
|
*/
|
|
function xml_format_document( $entry=array() )
|
|
{
|
|
$this->header = '<?xml version="1.0" encoding="'.$this->doc_type.'"?'.'>';
|
|
|
|
$this->xml_document = $this->header ? $this->header."\n" : '';
|
|
|
|
$this->xml_document .= "<".$this->root_tag.$this->root_attributes.">\n";
|
|
|
|
$this->xml_document .= $this->tmp_doc;
|
|
|
|
$this->xml_document .= "\n</".$this->root_tag.">";
|
|
|
|
$this->tmp_doc = "";
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Set the root tags
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Set the root tag
|
|
*
|
|
* @param string Root tag name
|
|
* @param array Root tag attributes
|
|
* @return void
|
|
*/
|
|
function xml_set_root($tag, $attributes=array() )
|
|
{
|
|
$this->root_tag = $tag;
|
|
$this->root_attributes = $this->_xml_build_attribute_string( $attributes );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Add entries to the group
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Add entry to XML group
|
|
*
|
|
* @param string Tag name
|
|
* @param array Entry values
|
|
* @return void
|
|
*/
|
|
|
|
function xml_add_entry_to_group($tag, $entry=array() )
|
|
{
|
|
$this->tmp_doc .= "\t".$this->groups[ $tag ];
|
|
|
|
if ( is_array( $entry ) and count( $entry ) )
|
|
{
|
|
foreach( $entry as $e )
|
|
{
|
|
$this->tmp_doc .= "\n\t\t".$e."\n";
|
|
}
|
|
}
|
|
|
|
$this->tmp_doc .= "\t</".$tag.">\n";
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Builds an entry
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Build an XML entry
|
|
*
|
|
* @param string Tag name
|
|
* @param array Content array
|
|
* @param array Attributes
|
|
* @return string
|
|
*/
|
|
|
|
function xml_build_entry( $tag, $content=array(), $attributes=array() )
|
|
{
|
|
$entry = "<" . $tag . $this->_xml_build_attribute_string($attributes) . ">\n";
|
|
|
|
if ( is_array( $content ) and count( $content ) )
|
|
{
|
|
foreach( $content as $c )
|
|
{
|
|
$entry .= "\t\t\t".$c."\n";
|
|
}
|
|
}
|
|
|
|
$entry .= "\t\t</" . $tag . ">";
|
|
|
|
return $entry;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Add a group
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Add a group to an XML document
|
|
*
|
|
* @param string Tag name
|
|
* @param array Attributes
|
|
* @return string
|
|
*/
|
|
function xml_add_group( $tag, $attributes=array() )
|
|
{
|
|
$this->groups[ $tag ] = "<" . $tag . $this->_xml_build_attribute_string($attributes) . ">";
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Builds a simple <tag [key="value"]>content</tag> structure
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Build and XML simple tag
|
|
*
|
|
* @param string Tag name
|
|
* @param string Tag value
|
|
* @param array Attributes
|
|
* @return string
|
|
*/
|
|
function xml_build_simple_tag( $tag, $description="", $attributes=array() )
|
|
{
|
|
return "<" . $tag . $this->_xml_build_attribute_string($attributes) . ">" . $this->_xml_encode_string($description) . "</" . $tag . ">";
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// INTERNAL: Build tree node
|
|
// Adapted from http://eric.pollmann.net/work/public_domain/
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Build tree node
|
|
*
|
|
* @param array Values
|
|
* @param array Values
|
|
* @param string Counter
|
|
* @param string Tag type
|
|
* @return array
|
|
*/
|
|
function _xml_build_tag( $thisvals, $vals, &$i, $type )
|
|
{
|
|
$tag = array();
|
|
|
|
if ( isset($thisvals['attributes']) )
|
|
{
|
|
$tag['ATTRIBUTES'] = $this->_xml_decode_attribute($thisvals['attributes']);
|
|
}
|
|
|
|
if ( $type === 'complete' )
|
|
{
|
|
$tag['VALUE'] = $this->_xml_unconvert_safecdata($thisvals['value']);
|
|
}
|
|
else
|
|
{
|
|
$tag = array_merge( $tag, $this->_xml_get_children($vals, $i) );
|
|
}
|
|
|
|
return $tag;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// INTERNAL: Build a nested array of children
|
|
// Adapted from http://eric.pollmann.net/work/public_domain/
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Build a nested array of children
|
|
*
|
|
* @param array Values
|
|
* @param string Counter
|
|
* @return array
|
|
*/
|
|
|
|
function _xml_get_children($vals, &$i)
|
|
{
|
|
$children = array();
|
|
|
|
//-----------------------------------
|
|
// CDATA before children
|
|
//-----------------------------------
|
|
|
|
if ( $i > -1 && isset( $vals[$i]['value'] ) )
|
|
{
|
|
$children['VALUE'] = $this->_xml_unconvert_safecdata( $vals[$i]['value'] );
|
|
}
|
|
|
|
//-----------------------------------
|
|
// Loopy loo
|
|
//-----------------------------------
|
|
|
|
while( ++$i < count( $vals ) )
|
|
{
|
|
$type = $vals[$i]['type'];
|
|
|
|
//-----------------------------------
|
|
// CDATA after children
|
|
//-----------------------------------
|
|
|
|
if ($type === 'cdata')
|
|
{
|
|
$children['VALUE'] .= $this->_xml_unconvert_safecdata( $vals[$i]['value'] );
|
|
}
|
|
|
|
//-----------------------------------
|
|
// COMPLETE: At end of current branch
|
|
// OPEN: Node has children, recurse
|
|
//-----------------------------------
|
|
|
|
else if ( $type === 'complete' OR $type === 'open' )
|
|
{
|
|
$tag = $this->_xml_build_tag( $vals[$i], $vals, $i, $type );
|
|
|
|
if ( $this->index_numeric )
|
|
{
|
|
$tag['TAG'] = $vals[$i]['tag'];
|
|
$children[] = $tag;
|
|
}
|
|
else
|
|
{
|
|
$children[$vals[$i]['tag']][] = $tag;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------
|
|
// End of node?
|
|
//-----------------------------------
|
|
|
|
else if ($type === 'close')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( $this->collapse_dups )
|
|
{
|
|
foreach( $children as $key => $value )
|
|
{
|
|
if ( is_array($value) && (count($value) == 1) )
|
|
{
|
|
$children[$key] = $value[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $children;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// INTERNAL: Builds attribute string
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Builds attribute string
|
|
*
|
|
* @param array Values
|
|
* @return string
|
|
*/
|
|
|
|
function _xml_build_attribute_string( $array = array() )
|
|
{
|
|
if ( is_array( $array ) and count( $array ) )
|
|
{
|
|
$string = array();
|
|
|
|
foreach( $array as $k => $v )
|
|
{
|
|
$v = trim( $this->_xml_encode_attribute($v) );
|
|
|
|
$string[] = $k.'="'.$v.'"';
|
|
}
|
|
|
|
return ' ' . implode( " ", $string );
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// INTERNAL: Encodes an attribute string
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Encode XML attribute (Make safe for transport)
|
|
*
|
|
* @param string Raw data
|
|
* @return string Converted Data
|
|
*/
|
|
function _xml_encode_attribute( $t )
|
|
{
|
|
$t = preg_replace("/&(?!#[0-9]+;)/s", '&', $t );
|
|
$t = str_replace( "<", "<" , $t );
|
|
$t = str_replace( ">", ">" , $t );
|
|
$t = str_replace( '"', """, $t );
|
|
$t = str_replace( "'", ''', $t );
|
|
|
|
return $t;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// INTERNAL: Encodes an attribute string
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Decode XML attribute (Make safe for transport)
|
|
*
|
|
* @param string Raw data
|
|
* @return string Converted Data
|
|
*/
|
|
function _xml_decode_attribute( $t )
|
|
{
|
|
$t = str_replace( "&" , "&", $t );
|
|
$t = str_replace( "<" , "<", $t );
|
|
$t = str_replace( ">" , ">", $t );
|
|
$t = str_replace( """, '"', $t );
|
|
$t = str_replace( "'", "'", $t );
|
|
|
|
return $t;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// INTERNAL: Encodes a string to make it safe (uses cdata)
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Encode XML attribute (Make safe for transport)
|
|
*
|
|
* @param string Raw data
|
|
* @return string Converted Data
|
|
*/
|
|
|
|
function _xml_encode_string( $v )
|
|
{
|
|
if ( preg_match( "/['\"\[\]<>&]/", $v ) )
|
|
{
|
|
$v = "<![CDATA[" . $this->_xml_convert_safecdata($v) . "]]>";
|
|
}
|
|
|
|
if ( $this->collapse_newlines )
|
|
{
|
|
$v = str_replace( "\r\n", "\n", $v );
|
|
}
|
|
|
|
return $v;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// INTERNAL: Ensures no embedding of cdata
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Encode CDATA XML attribute (Make safe for transport)
|
|
*
|
|
* @param string Raw data
|
|
* @return string Converted Data
|
|
*/
|
|
|
|
function _xml_convert_safecdata( $v )
|
|
{
|
|
# Legacy
|
|
//$v = str_replace( "<![CDATA[", "<!¢|CDATA|", $v );
|
|
//$v = str_replace( "]]>" , "|¢]>" , $v );
|
|
|
|
# New
|
|
$v = str_replace( "<![CDATA[", "<!#^#|CDATA|", $v );
|
|
$v = str_replace( "]]>" , "|#^#]>" , $v );
|
|
|
|
return $v;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// INTERNAL: Uncoverts safe embedding
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Decode CDATA XML attribute (Make safe for transport)
|
|
*
|
|
* @param string Raw data
|
|
* @return string Converted Data
|
|
*/
|
|
|
|
function _xml_unconvert_safecdata( $v )
|
|
{
|
|
# Legacy
|
|
$v = str_replace( "<!¢|CDATA|", "<![CDATA[", $v );
|
|
$v = str_replace( "|¢]>" , "]]>" , $v );
|
|
|
|
# New
|
|
$v = str_replace( "<!#^#|CDATA|", "<![CDATA[", $v );
|
|
$v = str_replace( "|#^#]>" , "]]>" , $v );
|
|
|
|
return $v;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//======================================================================================
|
|
// CLASS: XML_LITE_PARSE (Takes parsed XML and puts into EXPAT compatible array
|
|
//======================================================================================
|
|
|
|
/**
|
|
* XML-LITE Extraction
|
|
*
|
|
* Methods and functions for handling XML documents
|
|
*
|
|
* @package IPS_KERNEL
|
|
* @subpackage XMLHandling
|
|
* @author Matt Mecham
|
|
* @version 2.1
|
|
*/
|
|
class xml_lite_parse
|
|
{
|
|
var $xml_class;
|
|
var $parser;
|
|
var $preserve_cdata = 1;
|
|
var $stack = array();
|
|
var $level = 1;
|
|
var $tagname = "";
|
|
var $array_id = 0;
|
|
var $last_id = 0;
|
|
var $tagopen = array();
|
|
var $xmldoc = "";
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// CONSTRUCTOR
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function xml_lite_parse()
|
|
{
|
|
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Main parser
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function xml_parse_it( $xmldoc )
|
|
{
|
|
$parser = new xml_extract();
|
|
|
|
$this->xmldoc = $xmldoc;
|
|
|
|
unset( $xmldoc );
|
|
|
|
//-----------------------------------------
|
|
// Set up element handlers
|
|
//-----------------------------------------
|
|
|
|
$parser->my_xml_set_element_handler( array(&$this, 'my_start_element'), array(&$this, 'my_end_element') );
|
|
$parser->my_xml_set_character_data_handler(array(&$this, 'my_data_element'));
|
|
|
|
if ( $this->preserve_cdata )
|
|
{
|
|
$parser->my_xml_set_cdata_section_handler( array(&$this, 'my_cdata_element') );
|
|
}
|
|
|
|
$parser->xml_parse_document( $this->xmldoc );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Start element
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function my_start_element( &$parser_obj, $name, $attr )
|
|
{
|
|
//-------------------------------
|
|
// Add to stack
|
|
//-------------------------------
|
|
|
|
$this->stack[ $this->array_id ] = array( 'tag' => $name,
|
|
'type' => 'open',
|
|
'level' => $this->level,
|
|
'value' => '',
|
|
);
|
|
|
|
//-------------------------------
|
|
// Attributes?
|
|
//-------------------------------
|
|
|
|
if ( is_array( $attr ) and count( $attr ) )
|
|
{
|
|
$this->stack[ $this->array_id ]['attributes'] = $attr;
|
|
}
|
|
|
|
//-------------------------------
|
|
// Flying higher than an eagle?
|
|
//-------------------------------
|
|
|
|
if ( $this->tagname != $name )
|
|
{
|
|
if ( $this->tagopen[ $name ] )
|
|
{
|
|
$this->level = $this->tagopen[ $name ];
|
|
}
|
|
else
|
|
{
|
|
$this->level++;
|
|
}
|
|
}
|
|
|
|
//-------------------------------
|
|
// Set current tag name
|
|
//-------------------------------
|
|
|
|
$this->tagname = $name;
|
|
|
|
//-------------------------------
|
|
// Inc. array ID
|
|
//-------------------------------
|
|
|
|
$this->array_id++;
|
|
|
|
//-------------------------------
|
|
// Set tag == depth
|
|
//-------------------------------
|
|
|
|
$this->tagopen[ $name ] = $this->level;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Start element
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function my_end_element( &$parser_obj, $name )
|
|
{
|
|
$this->stack[ $this->array_id ] = array( 'tag' => $name,
|
|
'type' => 'close',
|
|
'level' => $this->tagopen[ $name ] - 1,
|
|
);
|
|
|
|
//-------------------------------
|
|
// Update already done data?
|
|
//-------------------------------
|
|
|
|
if ( ( $this->stack[ $this->array_id - 2 ]['tag'] == $this->tagname )
|
|
AND
|
|
( $this->stack[ $this->array_id - 1 ]['_data'] == 1 )
|
|
)
|
|
{
|
|
//-------------------------------
|
|
// Update previous tag
|
|
//-------------------------------
|
|
|
|
$this->stack[ $this->array_id - 2 ]['value'] = class_xml::_xml_unconvert_safecdata( $this->stack[ $this->array_id - 1 ]['value'] );
|
|
$this->stack[ $this->array_id - 2 ]['type'] = 'complete';
|
|
|
|
unset( $this->stack[ $this->array_id - 1 ] );
|
|
unset( $this->stack[ $this->array_id ] );
|
|
|
|
$this->array_id -= 2;
|
|
$this->last_id = $this->array_id - 1;
|
|
}
|
|
|
|
$this->tagname = "";
|
|
|
|
$this->array_id++;
|
|
$this->level--;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// DATA element
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function my_data_element( &$parser_obj, $data )
|
|
{
|
|
if ( $this->tagname )
|
|
{
|
|
$this->stack[ $this->array_id ] = array( 'tag' => $this->tagname,
|
|
'type' => 'open',
|
|
'level' => $this->level,
|
|
'value' => class_xml::_xml_unconvert_safecdata($data),
|
|
'_data' => 1
|
|
);
|
|
}
|
|
|
|
//-------------------------------
|
|
// Inc. array ID
|
|
//-------------------------------
|
|
|
|
$this->array_id++;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// CDATA element
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function my_cdata_element( &$parser_obj, $data )
|
|
{
|
|
$this->my_data_element( &$parser_obj, $data );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Free memory
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function garbage_collect()
|
|
{
|
|
$this->stack = array();
|
|
$this->tagname = array();
|
|
$this->array_id = 0;
|
|
$this->level = 0;
|
|
$this->xmldoc = "";
|
|
}
|
|
|
|
}
|
|
|
|
//======================================================================================
|
|
// CLASS: XML_EXTRACT (Parses XML file)
|
|
//======================================================================================
|
|
|
|
/**
|
|
* XML-LITE Extraction Sub class
|
|
*
|
|
* Methods and functions for handling XML documents
|
|
*
|
|
* @package IPS_KERNEL
|
|
* @subpackage XMLHandling
|
|
* @author Matt Mecham
|
|
* @version 2.1
|
|
*/
|
|
class xml_extract
|
|
{
|
|
var $xml_array = array();
|
|
var $chr_sofar = "";
|
|
var $handler_cdata_handler;
|
|
var $handler_character_data;
|
|
var $handler_end_element;
|
|
var $handler_start_element;
|
|
|
|
//-----------------------------------------
|
|
// Definitions
|
|
//-----------------------------------------
|
|
|
|
var $xml_constants = array(
|
|
'CDATA_TAG' => '![CDATA[',
|
|
'CDATA_LEN' => 8,
|
|
'NOTATION' => '!NOTATION',
|
|
'DOCTYPE' => '!DOCTYPE'
|
|
);
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// CONSTRUCTOR
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function xml_extract()
|
|
{
|
|
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// MAIN "PARSE" ROUTINE (Roughly mime EXPAT in PHP)
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function xml_parse_document( $xml )
|
|
{
|
|
//-----------------------------------------
|
|
// Grab all relevant XML data
|
|
// Strip off header, DOC TYPE, etc
|
|
//-----------------------------------------
|
|
|
|
$xml = preg_replace( "#^(?:.+?)?(<.*>)(?:.+?)?$#s", "\\1", $xml );
|
|
|
|
$xml_strlen = strlen( $xml );
|
|
|
|
//-----------------------------------------
|
|
// Pick through, char by char
|
|
//-----------------------------------------
|
|
|
|
for( $i = 0 ; $i < $xml_strlen; $i++ )
|
|
{
|
|
$chr = $xml{$i};
|
|
|
|
switch( $chr )
|
|
{
|
|
case '<':
|
|
if ( substr( $this->chr_sofar, 0, $this->xml_constants['CDATA_LEN'] ) == $this->xml_constants['CDATA_TAG'] )
|
|
{
|
|
//-----------------------------------------
|
|
// Processing CDATA
|
|
//-----------------------------------------
|
|
|
|
$this->chr_sofar .= $chr;
|
|
}
|
|
else
|
|
{
|
|
$this->parse_between_tags( $this->chr_sofar );
|
|
$this->chr_sofar = '';
|
|
}
|
|
break;
|
|
case '>':
|
|
if (
|
|
( substr( $this->chr_sofar, 0, $this->xml_constants['CDATA_LEN'] ) == $this->xml_constants['CDATA_TAG'] )
|
|
AND
|
|
! (
|
|
( $this->_get_nth_char_from_end( $this->chr_sofar, 0 ) == ']' )
|
|
AND
|
|
( $this->_get_nth_char_from_end( $this->chr_sofar, 1 ) == ']' )
|
|
)
|
|
)
|
|
{
|
|
$this->chr_sofar .= $chr;
|
|
}
|
|
else
|
|
{
|
|
if( $xml{ strlen($this->chr_sofar +1) } == ']' )
|
|
{
|
|
$this->chr_sofar .= $chr;
|
|
}
|
|
else
|
|
{
|
|
$this->parse_tag( $this->chr_sofar );
|
|
$this->chr_sofar = '';
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
$this->chr_sofar .= $chr;
|
|
}
|
|
}
|
|
|
|
unset($xml);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Parse tag
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function parse_tag( $text )
|
|
{
|
|
$attr = array();
|
|
$text = trim($text);
|
|
$fchr = $text{0};
|
|
|
|
switch ($fchr)
|
|
{
|
|
//-----------------------------------------
|
|
// First char is closing tag?
|
|
//-----------------------------------------
|
|
case '/':
|
|
|
|
$tag_name = substr($text, 1);
|
|
$this->exec_end_element($tag_name);
|
|
break;
|
|
//-----------------------------------------
|
|
// First char is instruction/doctype?
|
|
//-----------------------------------------
|
|
case '!':
|
|
|
|
$uc_tag_text = strtoupper($text);
|
|
|
|
if ( strpos($uc_tag_text, $this->xml_constants['CDATA_TAG']) !== false )
|
|
{
|
|
//-----------------------------------------
|
|
// CDATA text
|
|
//-----------------------------------------
|
|
|
|
$total = strlen($text);
|
|
$openbrace_cnt = 0;
|
|
$tn_text = '';
|
|
|
|
for ( $i = 0; $i < $total; $i++ )
|
|
{
|
|
$cc = $text{$i};
|
|
|
|
//-----------------------------------------
|
|
// End of CDATA?
|
|
//-----------------------------------------
|
|
|
|
if ( ($cc == ']') && ( $text{($i + 1)} == ']' ) )
|
|
{
|
|
if( ! $text{($i + 2)} == ']' )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
$tn_text .= $cc;
|
|
}
|
|
}
|
|
else if ($openbrace_cnt > 1)
|
|
{
|
|
$tn_text .= $cc;
|
|
}
|
|
else if ($cc == '[')
|
|
{
|
|
//-----------------------------------------
|
|
// Won't get here until first OB reached
|
|
//-----------------------------------------
|
|
|
|
$openbrace_cnt ++;
|
|
}
|
|
}
|
|
|
|
if ( $this->handler_cdata_handler == null )
|
|
{
|
|
$this->exec_character_data($tn_text);
|
|
}
|
|
else
|
|
{
|
|
$this->exec_cdata_element($tn_text);
|
|
}
|
|
}
|
|
else if ( strpos( $uc_tag_text, $this->xml_constants['NOTATION'] ) !== false )
|
|
{
|
|
//-----------------------------------------
|
|
// !NOTATION? Ignore!
|
|
//-----------------------------------------
|
|
|
|
return;
|
|
}
|
|
else if ( substr($text, 0, 2) == '!-' )
|
|
{
|
|
//-----------------------------------------
|
|
// !Comment? Ignore!
|
|
//-----------------------------------------
|
|
|
|
return;
|
|
}
|
|
|
|
break;
|
|
//-----------------------------------------
|
|
// Case is ?INSTRUCTION?
|
|
//-----------------------------------------
|
|
case '?':
|
|
|
|
//-----------------------------------------
|
|
// Instruction? Ignore!
|
|
//-----------------------------------------
|
|
|
|
return;
|
|
//-----------------------------------------
|
|
// Normal tag - woohoo!
|
|
//-----------------------------------------
|
|
default:
|
|
|
|
if ( (strpos($text, '"') !== false) || (strpos($text, "'") !== false) )
|
|
{
|
|
$total = strlen($text);
|
|
$tag_name = '';
|
|
|
|
for ($i = 0; $i < $total; $i++)
|
|
{
|
|
$cc = $text{$i};
|
|
|
|
if ($cc == ' ')
|
|
{
|
|
$attr = $this->parse_attr(substr($text, $i));
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
$tag_name.= $cc;
|
|
}
|
|
}
|
|
|
|
if ( strrpos($text, '/') == ( strlen($text) - 1 ) )
|
|
{
|
|
$this->exec_start_element($tag_name, $attr);
|
|
$this->exec_end_element($tag_name);
|
|
}
|
|
else
|
|
{
|
|
$this->exec_start_element($tag_name, $attr);
|
|
}
|
|
}
|
|
else {
|
|
if ( strpos($text, '/') !== false )
|
|
{
|
|
$text = trim( substr( $text, 0, ( strrchr($text, '/' ) - 1 ) ) );
|
|
$this->exec_start_element($text, $attr);
|
|
$this->exec_end_element($text);
|
|
}
|
|
else
|
|
{
|
|
$this->exec_start_element($text, $attr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Parse Attributes
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function parse_attr( $text )
|
|
{
|
|
$text = trim($text);
|
|
$attr_array = array();
|
|
$query_entity = false;
|
|
|
|
$total = strlen($text);
|
|
$dump_key = '';
|
|
$dump_value = '';
|
|
$cur_state = 0; // 0 = none, 1 = key, 2 = value
|
|
$quote_type = '';
|
|
|
|
for ($i = 0; $i < $total; $i++)
|
|
{
|
|
$cc = $text{$i};
|
|
|
|
if ( $cur_state == 0 )
|
|
{
|
|
if ( trim($cc != '') )
|
|
{
|
|
$cur_state = 1;
|
|
}
|
|
}
|
|
|
|
switch ($cc)
|
|
{
|
|
//-----------------------------------------
|
|
// Tab and we're in a value?
|
|
//-----------------------------------------
|
|
case "\t":
|
|
if ( $cur_state == 2 )
|
|
{
|
|
$dump_value .= $cc;
|
|
}
|
|
else
|
|
{
|
|
$cc = '';
|
|
}
|
|
break;
|
|
//-----------------------------------------
|
|
// Newlines..
|
|
//-----------------------------------------
|
|
case "\n":
|
|
case "\r":
|
|
$cc = '';
|
|
break;
|
|
//-----------------------------------------
|
|
// Param value
|
|
//-----------------------------------------
|
|
case '=':
|
|
if ( $cur_state == 2 )
|
|
{
|
|
$dump_value .= $cc;
|
|
}
|
|
else
|
|
{
|
|
$cur_state = 2;
|
|
$quote_type = '';
|
|
$query_entity = false;
|
|
}
|
|
break;
|
|
//-----------------------------------------
|
|
// Quoted
|
|
//-----------------------------------------
|
|
case '"':
|
|
if ($cur_state == 2)
|
|
{
|
|
if ($quote_type == '')
|
|
{
|
|
$quote_type = '"';
|
|
}
|
|
else
|
|
{
|
|
if ($quote_type == $cc)
|
|
{
|
|
$attr_array[ trim($dump_key) ] = trim($dump_value);
|
|
$dump_key = $dump_value = $quote_type = '';
|
|
$cur_state = 0;
|
|
}
|
|
else
|
|
{
|
|
$dump_value .= $cc;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
//-----------------------------------------
|
|
// Quoted
|
|
//-----------------------------------------
|
|
case "'":
|
|
if ($cur_state == 2)
|
|
{
|
|
if ($quote_type == '')
|
|
{
|
|
$quote_type = "'";
|
|
}
|
|
else
|
|
{
|
|
if ($quote_type == $cc)
|
|
{
|
|
$attr_array[ trim($dump_key) ] = trim($dump_value);
|
|
$dump_key = $dump_value = $quote_type = '';
|
|
$cur_state = 0;
|
|
}
|
|
else
|
|
{
|
|
$dump_value .= $cc;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
//-----------------------------------------
|
|
// Entity?
|
|
//-----------------------------------------
|
|
case '&':
|
|
$query_entity = true;
|
|
$dump_value .= $cc;
|
|
break;
|
|
|
|
default:
|
|
if ($cur_state == 1)
|
|
{
|
|
$dump_key .= $cc;
|
|
}
|
|
else
|
|
{
|
|
$dump_value .= $cc;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $attr_array;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Parse between the element tags
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function parse_between_tags( $t )
|
|
{
|
|
if ( trim($t ) != '')
|
|
{
|
|
$this->exec_character_data($t);
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Exec_events
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function exec_character_data( $data )
|
|
{
|
|
call_user_func( $this->handler_character_data, $this, $data );
|
|
}
|
|
|
|
function exec_start_element( $tagname, $attr )
|
|
{
|
|
call_user_func( $this->handler_start_element, $this, $tagname, $attr );
|
|
}
|
|
|
|
function exec_end_element( $tagname )
|
|
{
|
|
call_user_func( $this->handler_end_element, $this, $tagname );
|
|
}
|
|
|
|
function exec_cdata_element( $data )
|
|
{
|
|
call_user_func( $this->handler_cdata_handler, $this, $data );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Set xml element handlers
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function my_xml_set_element_handler($startHandler, $endHandler)
|
|
{
|
|
$this->handler_start_element = $startHandler;
|
|
$this->handler_end_element = $endHandler;
|
|
}
|
|
|
|
function my_xml_set_character_data_handler($handler)
|
|
{
|
|
$this->handler_character_data = &$handler;
|
|
}
|
|
|
|
function my_xml_set_cdata_section_handler($handler)
|
|
{
|
|
$this->handler_cdata_handler = &$handler;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
// Internal: Get nth character of $text
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
function _get_nth_char_from_end( $t, $i )
|
|
{
|
|
return $t{ ( strlen( $t ) - 1 - $i ) };
|
|
}
|
|
}
|
|
|
|
|
|
?>
|