PHP
downloads | documentation | faq | getting help | mailing lists | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

utf8_decode> <xdiff_string_patch
Last updated: Sun, 25 Nov 2007

view this page in

XML Parser Functions

Úvod

XML (eXtensible Markup Language) is a data format for structured document interchange on the Web. It is a standard defined by The World Wide Web consortium (W3C). Information about XML and related technologies can be found at » http://www.w3.org/XML/.

This PHP extension implements support for James Clark's expat in PHP. This toolkit lets you parse, but not validate, XML documents. It supports three source character encodings also provided by PHP: US-ASCII, ISO-8859-1 and UTF-8. UTF-16 is not supported.

This extension lets you create XML parsers and then define handlers for different XML events. Each XML parser also has a few parameters you can adjust.

Požiadavky

This extension uses an expat compat layer by default. It can use also expat, which can be found at » http://www.jclark.com/xml/expat.html. The Makefile that comes with expat does not build a library by default, you can use this make rule for that:

libexpat.a: $(OBJS)
    ar -rc $@ $(OBJS)
    ranlib $@
A source RPM package of expat can be found at » http://sourceforge.net/projects/expat/.

Inštalácia

These functions are enabled by default, using the bundled expat library. You can disable XML support with --disable-xml. If you compile PHP as a module for Apache 1.3.9 or later, PHP will automatically use the bundled expat library from Apache. In order you don't want to use the bundled expat library configure PHP --with-expat-dir=DIR, where DIR should point to the base installation directory of expat.

Windows verzie PHP majú vstavanú podporu pre toto rozšírenie. Nemusíte načítať žiadne dodatočné rozšírenie, aby ste mohli tieto funkcie používať.

Runtime Konfigurácia

Toto rozšírenie nemá žiadne konfiguračné direktívy definované v php.ini.

Typy zdrojov

xml

The xml resource as returned by xml_parser_create() and xml_parser_create_ns() references an xml parser instance to be used with the functions provided by this extension.

Preddefinované Konštanty

Konštanty uvedené nižšie sú definované týmto rozšírením a budú dostupné iba keď rozšírenie bolo buď kompilované do PHP alebo dynamicky načítané za behu (runtime).

XML_ERROR_NONE (integer)
XML_ERROR_NO_MEMORY (integer)
XML_ERROR_SYNTAX (integer)
XML_ERROR_NO_ELEMENTS (integer)
XML_ERROR_INVALID_TOKEN (integer)
XML_ERROR_UNCLOSED_TOKEN (integer)
XML_ERROR_PARTIAL_CHAR (integer)
XML_ERROR_TAG_MISMATCH (integer)
XML_ERROR_DUPLICATE_ATTRIBUTE (integer)
XML_ERROR_JUNK_AFTER_DOC_ELEMENT (integer)
XML_ERROR_PARAM_ENTITY_REF (integer)
XML_ERROR_UNDEFINED_ENTITY (integer)
XML_ERROR_RECURSIVE_ENTITY_REF (integer)
XML_ERROR_ASYNC_ENTITY (integer)
XML_ERROR_BAD_CHAR_REF (integer)
XML_ERROR_BINARY_ENTITY_REF (integer)
XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF (integer)
XML_ERROR_MISPLACED_XML_PI (integer)
XML_ERROR_UNKNOWN_ENCODING (integer)
XML_ERROR_INCORRECT_ENCODING (integer)
XML_ERROR_UNCLOSED_CDATA_SECTION (integer)
XML_ERROR_EXTERNAL_ENTITY_HANDLING (integer)
XML_OPTION_CASE_FOLDING (integer)
XML_OPTION_TARGET_ENCODING (integer)
XML_OPTION_SKIP_TAGSTART (integer)
XML_OPTION_SKIP_WHITE (integer)

Event Handlers

The XML event handlers defined are:

Supported XML handlers
PHP function to set handler Event description
xml_set_element_handler() Element events are issued whenever the XML parser encounters start or end tags. There are separate handlers for start tags and end tags.
xml_set_character_data_handler() Character data is roughly all the non-markup contents of XML documents, including whitespace between tags. Note that the XML parser does not add or remove any whitespace, it is up to the application (you) to decide whether whitespace is significant.
xml_set_processing_instruction_handler() PHP programmers should be familiar with processing instructions (PIs) already. <?php ?> is a processing instruction, where php is called the "PI target". The handling of these are application-specific, except that all PI targets starting with "XML" are reserved.
xml_set_default_handler() What goes not to another handler goes to the default handler. You will get things like the XML and document type declarations in the default handler.
xml_set_unparsed_entity_decl_handler() This handler will be called for declaration of an unparsed (NDATA) entity.
xml_set_notation_decl_handler() This handler is called for declaration of a notation.
xml_set_external_entity_ref_handler() This handler is called when the XML parser finds a reference to an external parsed general entity. This can be a reference to a file or URL, for example. See the external entity example for a demonstration.

Case Folding

The element handler functions may get their element names case-folded. Case-folding is defined by the XML standard as "a process applied to a sequence of characters, in which those identified as non-uppercase are replaced by their uppercase equivalents". In other words, when it comes to XML, case-folding simply means uppercasing.

By default, all the element names that are passed to the handler functions are case-folded. This behaviour can be queried and controlled per XML parser with the xml_parser_get_option() and xml_parser_set_option() functions, respectively.

Error Codes

The following constants are defined for XML error codes (as returned by xml_parse()):

  • XML_ERROR_NONE
  • XML_ERROR_NO_MEMORY
  • XML_ERROR_SYNTAX
  • XML_ERROR_NO_ELEMENTS
  • XML_ERROR_INVALID_TOKEN
  • XML_ERROR_UNCLOSED_TOKEN
  • XML_ERROR_PARTIAL_CHAR
  • XML_ERROR_TAG_MISMATCH
  • XML_ERROR_DUPLICATE_ATTRIBUTE
  • XML_ERROR_JUNK_AFTER_DOC_ELEMENT
  • XML_ERROR_PARAM_ENTITY_REF
  • XML_ERROR_UNDEFINED_ENTITY
  • XML_ERROR_RECURSIVE_ENTITY_REF
  • XML_ERROR_ASYNC_ENTITY
  • XML_ERROR_BAD_CHAR_REF
  • XML_ERROR_BINARY_ENTITY_REF
  • XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF
  • XML_ERROR_MISPLACED_XML_PI
  • XML_ERROR_UNKNOWN_ENCODING
  • XML_ERROR_INCORRECT_ENCODING
  • XML_ERROR_UNCLOSED_CDATA_SECTION
  • XML_ERROR_EXTERNAL_ENTITY_HANDLING

Character Encoding

PHP's XML extension supports the » Unicode character set through different character encodings. There are two types of character encodings, source encoding and target encoding. PHP's internal representation of the document is always encoded with UTF-8.

Source encoding is done when an XML document is parsed. Upon creating an XML parser, a source encoding can be specified (this encoding can not be changed later in the XML parser's lifetime). The supported source encodings are ISO-8859-1, US-ASCII and UTF-8. The former two are single-byte encodings, which means that each character is represented by a single byte. UTF-8 can encode characters composed by a variable number of bits (up to 21) in one to four bytes. The default source encoding used by PHP is ISO-8859-1.

Target encoding is done when PHP passes data to XML handler functions. When an XML parser is created, the target encoding is set to the same as the source encoding, but this may be changed at any point. The target encoding will affect character data as well as tag names and processing instruction targets.

If the XML parser encounters characters outside the range that its source encoding is capable of representing, it will return an error.

If PHP encounters characters in the parsed XML document that can not be represented in the chosen target encoding, the problem characters will be "demoted". Currently, this means that such characters are replaced by a question mark.

Príklady

Here are some example PHP scripts parsing XML documents.

XML Element Structure Example

This first example displays the structure of the start elements in a document with indentation.

Example#1 Show XML Element Structure

<?php
$file 
"data.xml";
$depth = array();

function 
startElement($parser$name$attrs
{
    global 
$depth;
    for (
$i 0$i $depth[$parser]; $i++) {
        echo 
"  ";
    }
    echo 
"$name\n";
    
$depth[$parser]++;
}

function 
endElement($parser$name
{
    global 
$depth;
    
$depth[$parser]--;
}

$xml_parser xml_parser_create();
xml_set_element_handler($xml_parser"startElement""endElement");
if (!(
$fp fopen($file"r"))) {
    die(
"could not open XML input");
}

while (
$data fread($fp4096)) {
    if (!
xml_parse($xml_parser$datafeof($fp))) {
        die(
sprintf("XML error: %s at line %d",
                    
xml_error_string(xml_get_error_code($xml_parser)),
                    
xml_get_current_line_number($xml_parser)));
    }
}
xml_parser_free($xml_parser);
?>

XML Tag Mapping Example

Example#2 Map XML to HTML

This example maps tags in an XML document directly to HTML tags. Elements not found in the "map array" are ignored. Of course, this example will only work with a specific XML document type.

<?php
$file 
"data.xml";
$map_array = array(
    
"BOLD"     => "B",
    
"EMPHASIS" => "I",
    
"LITERAL"  => "TT"
);

function 
startElement($parser$name$attrs
{
    global 
$map_array;
    if (isset(
$map_array[$name])) {
        echo 
"<$map_array[$name]>";
    }
}

function 
endElement($parser$name
{
    global 
$map_array;
    if (isset(
$map_array[$name])) {
        echo 
"</$map_array[$name]>";
    }
}

function 
characterData($parser$data
{
    echo 
$data;
}

$xml_parser xml_parser_create();
// use case-folding so we are sure to find the tag in $map_array
xml_parser_set_option($xml_parserXML_OPTION_CASE_FOLDINGtrue);
xml_set_element_handler($xml_parser"startElement""endElement");
xml_set_character_data_handler($xml_parser"characterData");
if (!(
$fp fopen($file"r"))) {
    die(
"could not open XML input");
}

while (
$data fread($fp4096)) {
    if (!
xml_parse($xml_parser$datafeof($fp))) {
        die(
sprintf("XML error: %s at line %d",
                    
xml_error_string(xml_get_error_code($xml_parser)),
                    
xml_get_current_line_number($xml_parser)));
    }
}
xml_parser_free($xml_parser);
?>

XML External Entity Example

This example highlights XML code. It illustrates how to use an external entity reference handler to include and parse other documents, as well as how PIs can be processed, and a way of determining "trust" for PIs containing code.

XML documents that can be used for this example are found below the example (xmltest.xml and xmltest2.xml.)

Example#3 External Entity Example

<?php
$file 
"xmltest.xml";

function 
trustedFile($file
{
    
// only trust local files owned by ourselves
    
if (!eregi("^([a-z]+)://"$file
        && 
fileowner($file) == getmyuid()) {
            return 
true;
    }
    return 
false;
}

function 
startElement($parser$name$attribs
{
    echo 
"&lt;<font color=\"#0000cc\">$name</font>";
    if (
count($attribs)) {
        foreach (
$attribs as $k => $v) {
            echo 
" <font color=\"#009900\">$k</font>=\"<font 
                   color=\"#990000\">$v</font>\""
;
        }
    }
    echo 
"&gt;";
}

function 
endElement($parser$name
{
    echo 
"&lt;/<font color=\"#0000cc\">$name</font>&gt;";
}

function 
characterData($parser$data
{
    echo 
"<b>$data</b>";
}

function 
PIHandler($parser$target$data
{
    switch (
strtolower($target)) {
        case 
"php":
            global 
$parser_file;
            
// If the parsed document is "trusted", we say it is safe
            // to execute PHP code inside it.  If not, display the code
            // instead.
            
if (trustedFile($parser_file[$parser])) {
                eval(
$data);
            } else {
                
printf("Untrusted PHP code: <i>%s</i>"
                        
htmlspecialchars($data));
            }
            break;
    }
}

function 
defaultHandler($parser$data
{
    if (
substr($data01) == "&" && substr($data, -11) == ";") {
        
printf('<font color="#aa00aa">%s</font>'
                
htmlspecialchars($data));
    } else {
        
printf('<font size="-1">%s</font>'
                
htmlspecialchars($data));
    }
}

function 
externalEntityRefHandler($parser$openEntityNames$base$systemId,
                                  
$publicId) {
    if (
$systemId) {
        if (!list(
$parser$fp) = new_xml_parser($systemId)) {
            
printf("Could not open entity %s at %s\n"$openEntityNames,
                   
$systemId);
            return 
false;
        }
        while (
$data fread($fp4096)) {
            if (!
xml_parse($parser$datafeof($fp))) {
                
printf("XML error: %s at line %d while parsing entity %s\n",
                       
xml_error_string(xml_get_error_code($parser)),
                       
xml_get_current_line_number($parser), $openEntityNames);
                
xml_parser_free($parser);
                return 
false;
            }
        }
        
xml_parser_free($parser);
        return 
true;
    }
    return 
false;
}

function 
new_xml_parser($file
{
    global 
$parser_file;

    
$xml_parser xml_parser_create();
    
xml_parser_set_option($xml_parserXML_OPTION_CASE_FOLDING1);
    
xml_set_element_handler($xml_parser"startElement""endElement");
    
xml_set_character_data_handler($xml_parser"characterData");
    
xml_set_processing_instruction_handler($xml_parser"PIHandler");
    
xml_set_default_handler($xml_parser"defaultHandler");
    
xml_set_external_entity_ref_handler($xml_parser"externalEntityRefHandler");
    
    if (!(
$fp = @fopen($file"r"))) {
        return 
false;
    }
    if (!
is_array($parser_file)) {
        
settype($parser_file"array");
    }
    
$parser_file[$xml_parser] = $file;
    return array(
$xml_parser$fp);
}

if (!(list(
$xml_parser$fp) = new_xml_parser($file))) {
    die(
"could not open XML input");
}

echo 
"<pre>";
while (
$data fread($fp4096)) {
    if (!
xml_parse($xml_parser$datafeof($fp))) {
        die(
sprintf("XML error: %s at line %d\n",
                    
xml_error_string(xml_get_error_code($xml_parser)),
                    
xml_get_current_line_number($xml_parser)));
    }
}
echo 
"</pre>";
echo 
"parse complete\n";
xml_parser_free($xml_parser);

?>

Example#4 xmltest.xml

<?xml version='1.0'?>
<!DOCTYPE chapter SYSTEM "/just/a/test.dtd" [
<!ENTITY plainEntity "FOO entity">
<!ENTITY systemEntity SYSTEM "xmltest2.xml">
]>
<chapter>
 <TITLE>Title &plainEntity;</TITLE>
 <para>
  <informaltable>
   <tgroup cols="3">
    <tbody>
     <row><entry>a1</entry><entry morerows="1">b1</entry><entry>c1</entry></row>
     <row><entry>a2</entry><entry>c2</entry></row>
     <row><entry>a3</entry><entry>b3</entry><entry>c3</entry></row>
    </tbody>
   </tgroup>
  </informaltable>
 </para>
 &systemEntity;
 <section id="about">
  <title>About this Document</title>
  <para>
   <!-- this is a comment -->
   <?php echo 'Hi!  This is PHP version ' . phpversion(); ?>
  </para>
 </section>
</chapter>

This file is included from xmltest.xml:

Example#5 xmltest2.xml

<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY testEnt "test entity">
]>
<foo>
   <element attrib="value"/>
   &testEnt;
   <?php echo "This is some more PHP code being executed."; ?>
</foo>

Table of Contents



utf8_decode> <xdiff_string_patch
Last updated: Sun, 25 Nov 2007
 
add a note add a note User Contributed Notes
XML
wolfon.AT-DoG.inbox.ru
28-Jul-2008 03:09
Finally a simple xml => array class.
Functioning like SimpleXML library.

<?php
class xml  {
    private
$parser;
    private
$pointer;
    public
$dom;
   
    public function
__construct($data) {
       
$this->pointer =& $this->dom;
       
$this->parser = xml_parser_create();
       
xml_set_object($this->parser, $this);
       
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false);
       
xml_set_element_handler($this->parser, "tag_open", "tag_close");
       
xml_set_character_data_handler($this->parser, "cdata");
       
xml_parse($this->parser, $data);
    }
  
    private function
tag_open($parser, $tag, $attributes) {
        if (isset(
$this->pointer[$tag]['@attributes'])) {
           
$content = $this->pointer[$tag];
           
$this->pointer[$tag] = array(0 => $content);
           
$idx = 1;
        } else if (isset(
$this->pointer[$tag]))
           
$idx = count($this->pointer[$tag]);

        if (isset(
$idx)) {
           
$this->pointer[$tag][$idx] = Array(
               
'@idx' => $idx,
               
'@parent' => &$this->pointer);
              
$this->pointer =& $this->pointer[$tag][$idx];
        } else {
           
$this->pointer[$tag] = Array(
               
'@parent' => &$this->pointer);
           
$this->pointer =& $this->pointer[$tag];
        }
        if (!empty(
$attributes))
           
$this->pointer['@attributes'] = $attributes;
    }

    private function
cdata($parser, $cdata) {
          
$this->pointer['@data'] = $cdata;
    }

    private function
tag_close($parser, $tag) {
       
$current = & $this->pointer;
        if (isset(
$this->pointer['@idx']))
            unset(
$current['@idx']);
       
       
$this->pointer = & $this->pointer['@parent'];
       
          unset(
$current['@parent']);
           if (isset(
$current['@data']) && count($current) == 1)
              
$current = $current['@data'];
           else if (empty(
$current['@data'])||$current['@data']==0)
               unset(
$current['@data']);
    }
}
?>

maybe I'll do some explanations on habr
Anonymous
18-May-2008 12:18
This is peace of the code. It edit xml file.
<?
$songs = Array();
function start_element($parser, $name, $attrs){
    global $songs;
    if($name == "song"){
        array_push($songs, $attrs);
    }
}
function end_element ($parser, $name){}
$playlist_string = file_get_contents("test.xml");
$parser = xml_parser_create();
xml_set_element_handler($parser, "start_element", "end_element");
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_parse($parser, $playlist_string) or die("Error parsing XML document.");
print "<br />";
if($_POST['action'] == "ins"){
    array_push($songs, Array(
                "title" => $_POST['title'],
                "artist" => $_POST['artist'],
                "path" => $_POST['path']));
    $songs_final = $songs;
}else if($_POST['action'] == "del"){
    $songs_final = Array();
    foreach($songs as $song){
        if($song['title'] != $_POST['title']){
            array_push($songs_final, $song);
        }
    }
}
$write_string = "<songs>";
foreach($songs_final as $song){

    $write_string .= "<song>";
    $write_string .= "<title>".$song['title']."</title>";
    $write_string .= "<artist>".$song['artist']."</artist>";
    $write_string .= "<path>".$song['path']."</path>";
    $write_string .= "</song>";

}
$write_string .= "</songs>";
$fp = fopen("test.xml", "w+");
fwrite($fp, $write_string) or die("Error writing to file");
fclose($fp);
print "<em>Song inserted or deleted successfully :)</em><br />";
print "<a href=\"index.php\" title=\"return\">Return</a>";
?>
galen dot senogles at gmail dot com
29-Apr-2008 01:48
An update to the function below.  Fixes a bug where the data of the first tag, would occasionally get appended to the beginning of the tag data of the second tag.

<?php

   
foreach($dom['child_nodes'][0]['child_nodes'] as $key => $value) {
     
$tagname  = $value['tag_name'];
      if(isset(
$value['child_nodes'][0])) {
       
$numarrays = count($value['child_nodes']);
        if(
$numarrays > 1) {
         
$contents = "";
          foreach(
$value['child_nodes'] as $key => $value2) {
           
$contents .= $value2;
          }
        }else {
         
$contents = $value['child_nodes'][0];
        }
      }else {
       
$contents = 'isempty';
      }
    
     
$artmp = array($tagname => $contents);
     
array_push_associative($xmlarray,$artmp);
      unset(
$artmp);
    }

?>
galen dot senogles at gmail dot com
25-Apr-2008 02:28
If anyone else is having issues figuring out how to utilize the xml class that people have created and  modified, don't worry as you are not alone.  It took me a bit to come up with a solution that I liked, but I feel this does the job quite nice.

I read through the entire structure of the xml file and create an associative array based on the tag names.

I didn't worry about tag attributes as I didn't need to use them; so remember that if you use this method, you are only getting the tag name and the data inside the tag...that is all, no attributes!!

I am not going to include the xml class as it has been copy pasted multiple times already on this thread. Just scroll down for the xml class.

First let me show just an example of the EXTREMELY simple xml structure I was working with. Again, you will need to make modifications depending on the structure of the xml file you are working with! (I know I could use simplexml but I have php4 and not 5).

<?xml version="1.0"?>
<menuitems>
  <menutype>1</menutype>
  <product>Just some product info</product>
  <shipping>some stuff</shipping>
</menuitems>

The custom associative array push function taken from:
http://us.php.net/manual/en/function.array-push.php#58705

The xml class file is located here:
http://us.php.net/manual/en/ref.xml.php#81910

<?php
   
// Obtain the exact path to the xml file
   
$xmlfile = "mydata.xml";
   
$fp = fopen($xmlfile,"r");             // open the xml file
   
$xml = fread($fp, filesize($xmlfile)); // read in the size of the file into the variable xml
   
fclose($fp);                           // close the stream
   
   
$xml_parser = new xml();  // create a new xml class instance
   
$xml_parser->parse($xml); // parse the variable xml which contains our xml data
   
$dom = $xml_parser->dom// make a variable that holds the entire dom

/*
      This part extracts the xml nodes from the dom and places them into an associative array.
      The associative array key is the name of the tag; the value is the tag contents.
      We simply create an array on the fly using the name and contents, and hit that array
      with our original array using the array_push_associative function. We then check if
      isset to prevent errors from being displayed.  If the tag contents are empty,
      I put the string isempty inside so I can easily check to see later if there is contents or not.
*/ 

   
$xmlarray = array(); // the array we are going to store the information within the tag
   
$contents = "";
   
    foreach(
$dom['child_nodes'][0]['child_nodes'] as $key => $value) {
     
$tagname  = $value['tag_name'];
      if(isset(
$value['child_nodes'][0])) {
       
$numarrays = count($value['child_nodes']);
        if(
$numarrays > 1) {
          foreach(
$value['child_nodes'] as $key => $value2) {
           
$contents .= $value2;
          }
        }else {
         
$contents = $value['child_nodes'][0];
        }
      }else {
       
$contents = 'isempty';
      }
     
     
$artmp = array($tagname => $contents);
     
array_push_associative($xmlarray,$artmp);
      unset(
$artmp);
    }

    unset(
$xml);        // free up resources
   
unset($xml_parser); // free up resources
   
unset($dom);        // free up resources
?>

You may be wondering why there is a nested count and foreach loop inside the main foreach loop.  The reason that exists is that the xml class that I am using in this example, the one that is four posts down from this one, has the wonderful behavior in that when something hits the length of 1024 characters, it creates a new element in the array and puts the next 1024 characters into that next element etc.  This caused me massive confusion as to why some of my data was getting cut off.

So say I wanted to display the data inside the product tag, all I would need to do is this:

<?php
  
echo $xmlarray['product']
?>

I sincerely hope this helps people figure out how to utilize the xml class quicker than I did!

If anyone has suggestions, modifications, or whatever, please post it here!

Thanks
galen dot senogles at gmail dot com
19-Apr-2008 12:10
I used shawn's code that is an ongoing fix/update of a very nice php 4 & 5 compatible class.

It works great, only it kept giving me errors when the array isn't set, (I have errors set to show all).
<?php
// Here is the old function that gave errors:
   
function makeChildNode() {
        if (!
is_array($this->pointer['child_nodes'])){
           
$this->pointer['child_nodes'] = array();
        }
        return
count($this->pointer['child_nodes']);
    }

// Here is the new function that does not spit errors:
   
function makeChildNode() {
        if (!isset(
$this->pointer['child_nodes'])){
           
$this->pointer['child_nodes'] = array();
        }
        return
count($this->pointer['child_nodes']);
    }

?>
shawn dot rapp at gmail dot com
03-Apr-2008 12:24
Well I posted my script with an example fread($fp, 4096) meaning that it will only read 4k.  It was just for a quick example.  If you used that to input data from a really long XML file to the parser that would be the problem.
you could replace the 4096 with filesize("file.xml") or try replacing that example test code part with:

$xml = implode('',file("http://localhost/test.xml"));
$xml_parser = new XML_Class();
$xml_parser->parse($xml);
print_r($xml_parser->dom);

I've tried to recreate your problems by posting entire howto of installing LDAP into character data space of a node and can't get it to fail.  Please email with more info if the above isn't the problem.
But on that routine you posted from that website.  The problem with that one is it seems to be padding with unnecessary arrays.  It will overwrite different nodes with the same name if they are within the same parent.  And the number one biggest issue for me is that it drops attributes.  That is totally bogus.  It's a lot cleaner to store most values in attributes than making a zillion nodes and storing the data for something small like a integer or a float as character data.
Example: 
<coords x="1.53234" y="56.287" z="4.32" />
VS
<coords><x>1.53234</x><y>56.287</y><z>4.32</z></coords>

To me the top is very readable where the later makes my eyes bleed.
Any ways what is good about the links code is the error checking.  Isolating all the code in the parse method instead of constructor so the object is recyclable. And than releases the xml parser.
I'm definitely going to be putting that stuff into my class after I post this note.
 
But let me know if its still truncating.
shawn dot rapp at gmail dot com
18-Mar-2008 07:52
The reason why you would want to make your own simplistic DOM parser is because a lack of compatible between PHP 4's domxml and PHP 5's dom.
So it is for portability without having to wrapper the two different DOMs.
If you need a simple light weight XML parser that is portable this is the best way.  If you are writing applications for a particular server and more concerned with functionality and speed go with a compiled in DOM.
Here is the fix to Emmetts code...

<?PHP
$fp
= fopen("test.xml","r");
$xml = fread($fp, 4096);
fclose($fp);
$xml_parser = new xml();
$xml_parser->parse($xml);
$dom = $xml_parser->dom;
print_r($dom);

class
xml  {
    var
$parser;
    var
$pointer;
    var
$dom;
    function
xml() {
       
$this->pointer =& $this->dom;
       
$this->parser = xml_parser_create();
       
xml_set_object($this->parser, $this);
       
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false);
       
xml_set_element_handler($this->parser, "tag_open", "tag_close");
       
xml_set_character_data_handler($this->parser, "cdata");
    }

    function
parse($data) {
       
xml_parse($this->parser, $data);
    }
  
    function
makeChildNode() {
        if (!
is_array($this->pointer['child_nodes'])){
           
$this->pointer['child_nodes'] = array();
        }
        return
count($this->pointer['child_nodes']);
    }

    function
tag_open($parser, $tag, $attributes) {
       
$idx = $this->makeChildNode();
       
$this->pointer['child_nodes'][$idx] = Array(
           
'_idx' => $idx,
           
'_parent' => &$this->pointer,
           
'tag_name' => $tag,
           
'attributes' => $attributes,
        );
       
$this->pointer =& $this->pointer['child_nodes'][$idx];
    }

    function
cdata($parser, $cdata) {
       
//drop text nodes that are just white space formatting characters
       
if (trim($cdata) != "") {
           
$idx = $this->makeChildNode();
           
$this->pointer['child_nodes'][$idx] = $cdata;
            }
    }

    function
tag_close($parser, $tag) {
       
$idx =& $this->pointer['_idx'];
       
$this->pointer =& $this->pointer['_parent'];
        unset(
$this->pointer['child_nodes'][$idx]['_idx']);
        unset(
$this->pointer['child_nodes'][$idx]['_parent']);
    }
}
?>
jesdisciple at gmail dot com
07-Mar-2008 02:00
@[emmett dot thesane at yahoo dot com]: That code didn't work for me, but it seems that using the DOM functions (http://php.net/manual/en/ref.dom.php) would be more efficient.
emmett dot thesane at yahoo dot com
10-Dec-2007 04:19
There's a couple of vital flaws in aquariusrick's example:
1. Multiple tags of the same name will overwrite one another.
2. Text nodes within an element are all strung together, with no information saved regarding their order with respect to non-text nodes.

It provided a good starting point, however, for a DOM-builder that *does* allow those things.  This should be a more familiar structure for people used to DOM-walking in the browser; children of each node are stored in "childNodes". Text nodes are simply a child node that is only a string, instead of an array.

$xml_parser = new xml();
$xml_parser->parse($xml);
$dom = $xml_parser->dom;
print_r($dom);

class xml  {
    var $parser;
    var $pointer;
    var $dom;
    function xml() {
        $this->pointer =& $this->dom;
        $this->parser = xml_parser_create();
        xml_set_object($this->parser, $this);
        xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false);
        xml_set_element_handler($this->parser, "tag_open", "tag_close");
        xml_set_character_data_handler($this->parser, "cdata");
    }

    function parse($data) {
        xml_parse($this->parser, $data);
    }
   
    function makeChildNode() {
        if (!isset($this->pointer['childNodes'])){
            $this->pointer['childNodes'] = array();
        }
        return count($this->pointer['childNodes']);
    }

    function tag_open($parser, $tag, $attributes) {
        $idx = $this->makeChildNode();
        $this->pointer['childNodes'][$idx] = Array(
            '_idx' => $idx,
            'tagName' => $tag,
            'parentNode' => &$this->pointer,
            'attributes' => $attributes,
        );
        $this->pointer =& $this->pointer['childNodes'][$idx];
    }

    function cdata($parser, $cdata) {
        $idx = $this->makeChildNode();
        $this->pointer['childNodes'][$idx] = $cdata;
        //text node -- has no other attributes than the content
    }

    function tag_close($parser, $tag) {
        $idx =& $this->pointer['_idx'];
        $this->pointer =& $this->pointer['_parent'];
        unset($this->pointer['childNodes'][$idx]['_idx']);
    }
}
aquariusrick
05-Dec-2007 08:43
Here's another attempt at a very simple script that parses XML into a structure:

<?php
#Usage:
    //$xml_parser = new xml();
    //$xml_parser->parse($xml);
    //$dom = $xml_parser->dom;

class xml  {
    var
$parser;
    var
$pointer;
    var
$dom;
    function
xml() {
       
$this->pointer =& $this->dom;
       
$this->parser = xml_parser_create();
       
xml_set_object($this->parser, $this);
       
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false);
       
xml_set_element_handler($this->parser, "tag_open", "tag_close");
       
xml_set_character_data_handler($this->parser, "cdata");
    }

    function
parse($data) {
       
xml_parse($this->parser, $data);
    }

    function
t