[ Index ]
 

Code source de eGroupWare 1.2.106-2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/phpgwapi/inc/ -> class.xml.inc.php (source)

   1  <?php
   2  
   3  //
   4  // +----------------------------------------------------------------------+
   5  // | <phpXML/> version 1.0                                                |
   6  // | Copyright (c) 2001 Michael P. Mehl. All rights reserved.             |
   7  // +----------------------------------------------------------------------+
   8  // | Latest releases are available at http://phpxml.org/. For feedback or |
   9  // | bug reports, please contact the author at mpm@phpxml.org. Thanks!    |
  10  // +----------------------------------------------------------------------+
  11  // | The contents of this file are subject to the Mozilla Public License  |
  12  // | Version 1.1 (the "License"); you may not use this file except in     |
  13  // | compliance with the License. You may obtain a copy of the License at |
  14  // | http://www.mozilla.org/MPL/                                          |
  15  // |                                                                      |
  16  // | Software distributed under the License is distributed on an "AS IS"  |
  17  // | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See  |
  18  // | the License for the specific language governing rights and           |
  19  // | limitations under the License.                                       |
  20  // |                                                                      |
  21  // | The Original Code is <phpXML/>.                                      |
  22  // |                                                                      |
  23  // | The Initial Developer of the Original Code is Michael P. Mehl.       |
  24  // | Portions created by Michael P. Mehl are Copyright (C) 2001 Michael   |
  25  // | P. Mehl. All Rights Reserved.                                        |
  26  // +----------------------------------------------------------------------+
  27  // | Authors:                                                             |
  28  // |   Michael P. Mehl <mpm@phpxml.org>                                   |
  29  // +----------------------------------------------------------------------+
  30  //
  31  
  32  /**
  33  * Class for accessing XML data through the XPath language.
  34  *
  35  * This class offers methods for accessing the nodes of a XML document using 
  36  * the XPath language. You can add or remove nodes, set or modify their 
  37  * content and their attributes. No additional PHP extensions like DOM XML 
  38  * or something similar are required to use these features.
  39  *
  40  * @link      http://www.phpxml.org/ Latest release of this class
  41  * @link      http://www.w3.org/TR/xpath W3C XPath Recommendation
  42  * @copyright Copyright (c) 2001 Michael P. Mehl. All rights reserved.
  43  * @author    Michael P. Mehl <mpm@phpxml.org>
  44  * @version   1.0 (2001-03-08)
  45  * @access    public
  46  */
  47  
  48  class XML
  49  {
  50      /**
  51      * List of all document nodes.
  52      *
  53      * This array contains a list of all document nodes saved as an
  54      * associative array.
  55      *
  56      * @access private
  57      * @var    array
  58      */
  59      var $nodes = array();
  60      
  61      /**
  62      * List of document node IDs.
  63      *
  64      * This array contains a list of all IDs of all document nodes that
  65      * are used for counting when adding a new node.
  66      *
  67      * @access private
  68      * @var    array
  69      */
  70      var $ids = array();
  71      
  72      /**
  73      * Current document path.
  74      *
  75      * This variable saves the current path while parsing a XML file and adding
  76      * the nodes being read from the file.
  77      *
  78      * @access private
  79      * @var    string
  80      */
  81      var $path = "";
  82      
  83      /**
  84      * Current document position.
  85      *
  86      * This variable counts the current document position while parsing a XML
  87      * file and adding the nodes being read from the file.
  88      *
  89      * @access private
  90      * @var    int
  91      */
  92      var $position = 0;
  93      
  94      /**
  95      * Path of the document root.
  96      *
  97      * This string contains the full path to the node that acts as the root
  98      * node of the whole document.
  99      *
 100      * @access private
 101      * @var    string
 102      */
 103      var $root = "";
 104      
 105      /**
 106      * Current XPath expression.
 107      *
 108      * This string contains the full XPath expression being parsed currently.
 109      *
 110      * @access private
 111      * @var    string
 112      */
 113      var $xpath    = "";
 114                                                                                  
 115      /**
 116      * List of entities to be converted.
 117      *
 118      * This array contains a list of entities to be converted when an XPath
 119      * expression is evaluated.
 120      *
 121      * @access private
 122      * @var    array
 123      */
 124      var $entities = array ( "&" => "&amp;", "<" => "&lt;", ">" => "&gt;",
 125          "'" => "&apos", '"' => "&quot;" );
 126      
 127      /**
 128      * List of supported XPath axes.
 129      *
 130      * This array contains a list of all valid axes that can be evaluated in an
 131      * XPath expression.
 132      *
 133      * @access private
 134      * @var    array
 135      */
 136      var $axes = array ( "child", "descendant", "parent", "ancestor",
 137          "following-sibling", "preceding-sibling", "following", "preceding",
 138          "attribute", "namespace", "self", "descendant-or-self",
 139          "ancestor-or-self" );
 140      
 141      /**
 142      * List of supported XPath functions.
 143      *
 144      * This array contains a list of all valid functions that can be evaluated
 145      * in an XPath expression.
 146      *
 147      * @access private
 148      * @var    array
 149      */
 150      var $functions = array ( "last", "position", "count", "id", "name",
 151          "string", "concat", "starts-with", "contains", "substring-before",
 152          "substring-after", "substring", "string-length", "translate",
 153          "boolean", "not", "true", "false", "lang", "number", "sum", "floor",
 154          "ceiling", "round", "text" );
 155      
 156      /**
 157      * List of supported XPath operators.
 158      *
 159      * This array contains a list of all valid operators that can be evaluated
 160      * in a predicate of an XPath expression. The list is ordered by the
 161      * precedence of the operators (lowest precedence first).
 162      *
 163      * @access private
 164      * @var    array
 165      */
 166      var $operators = array( " or ", " and ", "=", "!=", "<=", "<", ">=", ">",
 167          "+", "-", "*", " div ", " mod " );
 168  
 169      /**
 170      * Constructor of the class.
 171      *
 172      * This constructor initializes the class and, when a filename is given,
 173      * tries to read and parse the given file.
 174      *
 175      * @access    public
 176      * @author    Michael P. Mehl <mpm@phpxml.org>
 177      * @param     string $file Path and name of the file to read and parsed.
 178      * @see       load_file()
 179      */
 180      function XML ( $file = "" )
 181      {
 182          // Check whether a file was given.
 183          if ( !empty($file) )
 184          {
 185              // Load the XML file.
 186              $this->load_file($file);
 187          }
 188      }
 189  
 190      /**
 191      * Reads a file and parses the XML data.
 192      *
 193      * This method reads the content of a XML file, tries to parse its
 194      * content and upon success stores the information retrieved from
 195      * the file into an array.
 196      *
 197      * @access    public
 198      * @author    Michael P. Mehl <mpm@phpxml.org>
 199      * @param     string $file Path and name of the file to be read and parsed.
 200      * @see       handle_start_element(), handle_end_element(),
 201      *            handle_character_data()
 202      */
 203      function load_file ( $file )
 204      {
 205          // Check whether the file exists and is readable.
 206          if ( file_exists($file) && is_readable($file) )
 207          {
 208              // Read the content of the file.
 209              $content = implode("", file($file));
 210              
 211              // Check whether content has been read.
 212              if ( !empty($content) )
 213              {
 214                  // Create an XML parser.
 215                  $parser = xml_parser_create();
 216                  
 217                  // Set the options for parsing the XML data.
 218                  xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 
 219                  xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
 220                  
 221                  // Set the object for the parser.
 222                  xml_set_object($parser, &$this);
 223                  
 224                  // Set the element handlers for the parser.
 225                  xml_set_element_handler($parser, "handle_start_element",
 226                      "handle_end_element");
 227                  xml_set_character_data_handler($parser,
 228                      "handle_character_data");
 229                  
 230                  // Parse the XML file.
 231                  if ( !xml_parse($parser, $content, true) )
 232                  {
 233                      // Display an error message.
 234                      $this->display_error("XML error in file %s, line %d: %s",
 235                          $file, xml_get_current_line_number($parser),
 236                          xml_error_string(xml_get_error_code($parser)));
 237                  }
 238                  
 239                  // Free the parser.
 240                  xml_parser_free($parser);
 241              }
 242          }
 243          else
 244          {
 245              // Display an error message.
 246              $this->display_error("File %s could not be found or read.", $file);
 247          }
 248      }
 249      
 250      /**
 251      * Generates a XML file with the content of the current document.
 252      *
 253      * This method creates a string containing the XML data being read
 254      * and modified by this class before. This string can be used to save
 255      * a modified document back to a file or doing other nice things with
 256      * it.
 257      *
 258      * @access    public
 259      * @author    Michael P. Mehl <mpm@phpxml.org>
 260      * @param     array $highlight Array containing a list of full document
 261      *            paths of nodes to be highlighted by <font>...</font> tags
 262      *            in the generated XML string.
 263      * @param     string $root While doing a recursion with this method, this
 264      *            parameter is used for internal purpose.
 265      * @param     int $level While doing a recursion with this method, this
 266      *            parameter is used for internal purpose.
 267      * @return    string The returned string contains well-formed XML data
 268      *            representing the content of this document.
 269      * @see       load_file(), evaluate(), get_content()
 270      */
 271      function get_file ( $highlight = array(), $root = "", $level = 0 )
 272      {
 273          // Create a string to save the generated XML data.
 274          $xml = "";
 275          
 276          // Create two strings containing the tags for highlighting a node.
 277          $highlight_start = "<font color=\"#FF0000\"><b>";
 278          $highlight_end   = "</b></font>";
 279          
 280          // Generate a string to be displayed before the tags.
 281          $before = "";
 282          
 283          // Calculate the amount of whitespaces to display.
 284          for ( $i = 0; $i < ( $level * 2 ); $i++ )
 285          {
 286              // Add a whitespaces to the string.
 287              $before .= " ";
 288          }
 289          
 290          // Check whether a root node is given.
 291          if ( empty($root) )
 292          {
 293              // Set it to the document root.
 294              $root = $this->root;
 295          }
 296          
 297          // Check whether the node is selected.
 298          $selected = in_array($root, $highlight);
 299          
 300          // Now add the whitespaces to the XML data.
 301          $xml .= $before;
 302          
 303          // Check whether the node is selected.
 304          if ( $selected )
 305          {
 306              // Add the highlight code to the XML data.
 307              $xml .= $highlight_start;
 308          }
 309          
 310          // Now open the tag.
 311          $xml .= "&lt;".$this->nodes[$root]["name"];
 312          
 313          // Check whether there are attributes for this node.
 314          if ( count($this->nodes[$root]["attributes"]) > 0 )
 315          {
 316              // Run through all attributes.
 317              foreach ( $this->nodes[$root]["attributes"] as $key => $value )
 318              {
 319                  // Check whether this attribute is highlighted.
 320                  if ( in_array($root."/attribute::".$key, $highlight) )
 321                  {
 322                      // Add the highlight code to the XML data.
 323                      $xml .= $highlight_start;
 324                  }
 325                  
 326                  // Add the attribute to the XML data.
 327                  $xml .= " ".$key."=\"".trim(stripslashes($value))."\"";
 328                  
 329                  // Check whether this attribute is highlighted.
 330                  if ( in_array($root."/attribute::".$key, $highlight) )
 331                  {
 332                      // Add the highlight code to the XML data.
 333                      $xml .= $highlight_end;
 334                  }
 335              }
 336          }
 337          
 338          // Check whether the node contains character data or has children.
 339          if ( empty($this->nodes[$root]["text"]) &&
 340              !isset($this->nodes[$root]["children"]) )
 341          {
 342              // Add the end to the tag.
 343              $xml .= "/";
 344          }
 345          
 346          // Close the tag.
 347          $xml .= "&gt;\n";
 348          
 349          // Check whether the node is selected.
 350          if ( $selected )
 351          {
 352              // Add the highlight code to the XML data.
 353              $xml .= $highlight_end;
 354          }
 355          
 356          // Check whether the node contains character data.
 357          if ( !empty($this->nodes[$root]["text"]) )
 358          {
 359              // Add the character data to the XML data.
 360              $xml .= $before."  ".$this->nodes[$root]["text"]."\n";
 361          }
 362          
 363          // Check whether the node has children.
 364          if ( isset($this->nodes[$root]["children"]) )
 365          {
 366              // Run through all children with different names.
 367              foreach ( $this->nodes[$root]["children"] as $child => $pos )
 368              {
 369                  // Run through all children with the same name.
 370                  for ( $i = 1; $i <= $pos; $i++ )
 371                  {
 372                      // Generate the full path of the child.
 373                      $fullchild = $root."/".$child."[".$i."]";
 374                      
 375                      // Add the child's XML data to the existing data.
 376                      $xml .= $this->get_file($highlight, $fullchild,
 377                          $level + 1);
 378                  }
 379              }
 380          }
 381          
 382          // Check whether there are attributes for this node.
 383          if ( !empty($this->nodes[$root]["text"]) ||
 384              isset($this->nodes[$root]["children"]) )
 385          {
 386              // Add the whitespaces to the XML data.
 387              $xml .= $before;
 388              
 389              // Check whether the node is selected.
 390              if ( $selected )
 391              {
 392                  // Add the highlight code to the XML data.
 393                  $xml .= $highlight_start;
 394              }
 395              
 396              // Add the closing tag.
 397              $xml .= "&lt;/".$this->nodes[$root]["name"]."&gt;";
 398              
 399              // Check whether the node is selected.
 400              if ( $selected )
 401              {
 402                  // Add the highlight code to the XML data.
 403                  $xml .= $highlight_end;
 404              }
 405              
 406              // Add a linebreak.
 407              $xml .= "\n";
 408          }
 409          
 410          // Return the XML data.
 411          return $xml;
 412      }
 413      
 414      /**
 415      * Adds a new node to the XML document.
 416      *
 417      * This method adds a new node to the tree of nodes of the XML document
 418      * being handled by this class. The new node is created according to the
 419      * parameters passed to this method.
 420      *
 421      * @access    public
 422      * @author    Michael P. Mehl <mpm@phpxml.org>
 423      * @param     string $content Full path of the parent, to which the new
 424      *            node should be added as a child.
 425      * @param     string $name Name of the new node.
 426      * @return    string The string returned by this method will contain the
 427      *            full document path of the created node.
 428      * @see       remove_node(), evaluate()
 429      */
 430      function add_node ( $context, $name )
 431      {
 432          // Check whether a name for this element is already set.
 433          if ( empty($this->root) )
 434          {
 435              // Use this tag as the root element.
 436              $this->root = "/".$name."[1]";
 437          }
 438          
 439          // Calculate the full path for this element.
 440          $path = $context."/".$name;
 441          
 442          // Set the relative context and the position.
 443          $position = ++$this->ids[$path];
 444          $relative = $name."[".$position."]";
 445          
 446          // Calculate the full path.
 447          $fullpath = $context."/".$relative;
 448          
 449          // Calculate the context position, which is the position of this
 450          // element within elements of the same name in the parent node.
 451          $this->nodes[$fullpath]["context-position"] = $position;
 452          
 453          // Calculate the position for the following and preceding axis
 454          // detection.
 455          $this->nodes[$fullpath]["document-position"] =
 456              $this->nodes[$context]["document-position"] + 1;
 457          
 458          // Save the information about the node.
 459          $this->nodes[$fullpath]["name"]   = $name;
 460          $this->nodes[$fullpath]["text"]   = "";
 461          $this->nodes[$fullpath]["parent"] = $context;
 462          
 463          // Add this element to the element count array.
 464          if ( !$this->nodes[$context]["children"][$name] )
 465          {
 466              // Set the default name.
 467              $this->nodes[$context]["children"][$name] = 1;
 468          }
 469          else
 470          {
 471              // Calculate the name.
 472              $this->nodes[$context]["children"][$name] =
 473                  $this->nodes[$context]["children"][$name] + 1;
 474          }
 475          
 476          // Return the path of the new node.
 477          return $fullpath;
 478      }
 479  
 480      /**
 481      * Removes a node from the XML document.
 482      *
 483      * This method removes a node from the tree of nodes of the XML document.
 484      * If the node is a document node, all children of the node and its
 485      * character data will be removed. If the node is an attribute node,
 486      * only this attribute will be removed, the node to which the attribute
 487      * belongs as well as its children will remain unmodified.
 488      *
 489      * @access    public
 490      * @author    Michael P. Mehl <mpm@phpxml.org>
 491      * @param     string $node Full path of the node to be removed.
 492      * @see       add_node(), evaluate()
 493      */
 494      function remove_node ( $node )
 495      {
 496          // Check whether the node is an attribute node.
 497          if ( ereg("/attribute::", $node) )
 498          {
 499              // Get the path to the attribute node's parent.
 500              $parent = $this->prestr($node, "/attribute::");
 501              
 502              // Get the name of the attribute.
 503              $attribute = $this->afterstr($node, "/attribute::");
 504              
 505              // Check whether the attribute exists.
 506              if ( isset($this->nodes[$parent]["attributes"][$attribute]) )
 507              {
 508                  // Create a new array.
 509                  $new = array();
 510                  
 511                  // Run through the existing attributes.
 512                  foreach ( $this->nodes[$parent]["attributes"]
 513                      as $key => $value )
 514                  {
 515                      // Check whether it's the attribute to remove.
 516                      if ( $key != $attribute )
 517                      {
 518                          // Add it to the new array again.
 519                          $new[$key] = $value;
 520                      }
 521                  }
 522                  
 523                  // Save the new attributes.
 524                  $this->nodes[$parent]["attributes"] = $new;
 525              }
 526          }
 527          else
 528          {
 529              // Create an associative array, which contains information about
 530              // all nodes that required to be renamed.
 531              $rename = array();
 532              
 533              // Get the name, the parent and the siblings of current node.
 534              $name     = $this->nodes[$node]["name"];
 535              $parent   = $this->nodes[$node]["parent"];
 536              $siblings = $this->nodes[$parent]["children"][$name];
 537              
 538              // Decrease the number of children.
 539              $this->nodes[$parent]["children"][$name]--;
 540              
 541              // Create a counter for renumbering the siblings.
 542              $counter = 1;
 543              
 544              // Now run through the siblings.
 545              for ( $i = 1; $i <= $siblings; $i++ )
 546              {
 547                  // Create the name of the sibling.
 548                  $sibling = $parent."/".$name."[".$i."]";
 549                  
 550                  // Check whether it's the name of the current node.
 551                  if ( $sibling != $node )
 552                  {
 553                      // Create the new name for the sibling.
 554                      $new = $parent."/".$name."[".$counter."]";
 555                      
 556                      // Increase the counter.
 557                      $counter++;
 558                      
 559                      // Add the old and the new name to the list of nodes
 560                      // to be renamed.
 561                      $rename[$sibling] = $new;
 562                  }
 563              }
 564              
 565              // Create an array for saving the new node-list.
 566              $nodes = array();
 567              
 568              // Now run through through the existing nodes.
 569              foreach ( $this->nodes as $name => $values )
 570              {
 571                  // Check the position of the path of the node to be deleted
 572                  // in the path of the current node.
 573                  $position = strpos($name, $node);
 574  
 575                  // Check whether it's not the node to be deleted.
 576                  if ( $position === false )
 577                  {
 578                      // Run through the array of nodes to be renamed.
 579                      foreach ( $rename as $old => $new )
 580                      {
 581                          // Check whether this node and it's parent requires to
 582                          // be renamed.
 583                          $name             = str_replace($old, $new, $name);
 584                          $values["parent"] = str_replace($old, $new,
 585                              $values["parent"]);
 586                      }
 587                      
 588                      // Add the node to the list of nodes.
 589                      $nodes[$name] = $values;
 590                  }
 591              }
 592              
 593              // Save the new array of nodes.
 594              $this->nodes = $nodes;
 595          }
 596      }
 597  
 598      /**
 599      * Add content to a node.
 600      *
 601      * This method adds content to a node. If it's an attribute node, then
 602      * the value of the attribute will be set, otherwise the character data of
 603      * the node will be set. The content is appended to existing content,
 604      * so nothing will be overwritten.
 605      *
 606      * @access    public
 607      * @author    Michael P. Mehl <mpm@phpxml.org>
 608      * @param     string $path Full document path of the node.
 609      * @param     string $value String containing the content to be added.
 610      * @see       get_content(), evaluate()
 611      */
 612      function add_content ( $path, $value )
 613      {
 614          // Check whether it's an attribute node.
 615          if ( ereg("/attribute::", $path) )
 616          {
 617              // Get the path to the attribute node's parent.
 618              $parent = $this->prestr($path, "/attribute::");
 619              
 620              // Get the parent node.
 621              $parent = $this->nodes[$parent];
 622              
 623              // Get the name of the attribute.
 624              $attribute = $this->afterstr($path, "/attribute::");
 625              
 626              // Set the attribute.
 627              $parent["attributes"][$attribute] .= $value;
 628          }
 629          else
 630          {
 631              // Set the character data of the node.
 632              $this->nodes[$path]["text"] .= $value;
 633          }
 634      }
 635      
 636      /**
 637      * Set the content of a node.
 638      *
 639      * This method sets the content of a node. If it's an attribute node, then
 640      * the value of the attribute will be set, otherwise the character data of
 641      * the node will be set. Existing content will be overwritten.
 642      *
 643      * @access    public
 644      * @author    Michael P. Mehl <mpm@phpxml.org>
 645      * @param     string $path Full document path of the node.
 646      * @param     string $value String containing the content to be set.
 647      * @see       get_content(), evaluate()
 648      */
 649      function set_content ( $path, $value )
 650      {
 651          // Check whether it's an attribute node.
 652          if ( ereg("/attribute::", $path) )
 653          {
 654              // Get the path to the attribute node's parent.
 655              $parent = $this->prestr($path, "/attribute::");
 656              
 657              // Get the parent node.
 658              $parent = $this->nodes[$parent];
 659              
 660              // Get the name of the attribute.
 661              $attribute = $this->afterstr($path, "/attribute::");
 662              
 663              // Set the attribute.
 664              $parent["attributes"][$attribute] = $value;
 665          }
 666          else
 667          {
 668              // Set the character data of the node.
 669              $this->nodes[$path]["text"] = $value;
 670          }
 671      }
 672      
 673      /**
 674      * Retrieves the content of a node.
 675      *
 676      * This method retrieves the content of a node. If it's an attribute
 677      * node, then the value of the attribute will be retrieved, otherwise
 678      * it'll be the character data of the node.
 679      *
 680      * @access    public
 681      * @author    Michael P. Mehl <mpm@phpxml.org>
 682      * @param     string $path Full document path of the node, from which the
 683      *            content should be retrieved.
 684      * @return    string The returned string contains either the value or the
 685      *            character data of the node.
 686      * @see       set_content(), evaluate()
 687      */
 688      function get_content ( $path )
 689      {
 690          // Check whether it's an attribute node.
 691          if ( ereg("/attribute::", $path) )
 692          {
 693              // Get the path to the attribute node's parent.
 694              $parent = $this->prestr($path, "/attribute::");
 695              
 696              // Get the parent node.
 697              $parent = $this->nodes[$parent];
 698              
 699              // Get the name of the attribute.
 700              $attribute = $this->afterstr($path, "/attribute::");
 701              
 702              // Get the attribute.
 703              $attribute = $parent["attributes"][$attribute];
 704              
 705              // Return the value of the attribute.
 706              return $attribute;
 707          }
 708          else
 709          {
 710              // Return the cdata of the node.
 711              return stripslashes($this->nodes[$path]["text"]);
 712          }
 713      }
 714      
 715      /**
 716      * Add attributes to a node.
 717      *
 718      * This method adds attributes to a node. Existing attributes will not be
 719      * overwritten.
 720      *
 721      * @access    public
 722      * @author    Michael P. Mehl <mpm@phpxml.org>
 723      * @param     string $path Full document path of the node, the attributes
 724      *            should be added to.
 725      * @param     array $attributes Associative array containing the new
 726      *            attributes for the node.
 727      * @see       set_content(), get_content()
 728      */
 729      function add_attributes ( $path, $attributes )
 730      {
 731          // Add the attributes to the node.
 732          $this->nodes[$path]["attributes"] = array_merge($attributes,
 733              $this->nodes[$path]["attributes"]);
 734      }
 735      
 736      /**
 737      * Sets the attributes of a node.
 738      *
 739      * This method sets the attributes of a node and overwrites all existing
 740      * attributes by doing this.
 741      *
 742      * @access    public
 743      * @author    Michael P. Mehl <mpm@phpxml.org>
 744      * @param     string $path Full document path of the node, the attributes
 745      *            of which should be set.
 746      * @param     array $attributes Associative array containing the new
 747      *            attributes for the node.
 748      * @see       set_content(), get_content()
 749      */
 750      function set_attributes ( $path, $attributes )
 751      {
 752          // Set the attributes of the node.
 753          $this->nodes[$path]["attributes"] = $attributes;
 754      }
 755      
 756      /**
 757      * Retrieves a list of all attributes of a node.
 758      *
 759      * This method retrieves a list of all attributes of the node specified in
 760      * the argument.
 761      *
 762      * @access    public
 763      * @author    Michael P. Mehl <mpm@phpxml.org>
 764      * @param     string $path Full document path of the node, from which the
 765      *            list of attributes should be retrieved.
 766      * @return    array The returned associative array contains the all
 767      *            attributes of the specified node.
 768      * @see       get_content(), $nodes, $ids
 769      */
 770      function get_attributes ( $path )
 771      {
 772          // Return the attributes of the node.
 773          return $this->nodes[$path]["attributes"];
 774      }
 775      
 776      /**
 777      * Retrieves the name of a document node.
 778      *
 779      * This method retrieves the name of document node specified in the
 780      * argument.
 781      *
 782      * @access    public
 783      * @author    Michael P. Mehl <mpm@phpxml.org>
 784      * @param     string $path Full document path of the node, from which the
 785      *            name should be retrieved.
 786      * @return    string The returned array contains the name of the specified
 787      *            node.
 788      * @see       get_content(), $nodes, $ids
 789      */
 790      function get_name ( $path )
 791      {
 792          // Return the name of the node.
 793          return $this->nodes[$path]["name"];
 794      }
 795      
 796      /**
 797      * Evaluates an XPath expression.
 798      *
 799      * This method tries to evaluate an XPath expression by parsing it. A
 800      * XML document has to be read before this method is able to work.
 801      *
 802      * @access    public
 803      * @author    Michael P. Mehl <mpm@phpxml.org>
 804      * @param     string $path XPath expression to be evaluated.
 805      * @param     string $context Full path of a document node, starting
 806      *            from which the XPath expression should be evaluated.
 807      * @return    array The returned array contains a list of the full
 808      *            document paths of all nodes that match the evaluated
 809      *            XPath expression.
 810      * @see       $nodes, $ids
 811      */
 812      function evaluate ( $path, $context = "" )
 813      {
 814          // Remove slashes and quote signs.
 815          $path = stripslashes($path);
 816          $path = str_replace("\"", "", $path);
 817          $path = str_replace("'", "", $path);
 818          
 819          // Split the paths into different paths.
 820          $paths = $this->split_paths($path);
 821          
 822          // Create an empty set to save the result.
 823          $result = array();
 824          
 825          // Run through all paths.
 826          foreach ( $paths as $path )
 827          {
 828              // Trim the path.
 829              $path = trim($path);
 830              
 831              // Save the current path.
 832              $this->xpath = $path;
 833          
 834              // Convert all entities.
 835              $path = strtr($path, array_flip($this->entities));
 836          
 837              // Split the path at every slash.
 838              $steps = $this->split_steps($path);
 839          
 840              // Check whether the first element is empty.
 841              if ( empty($steps[0]) )
 842              {
 843                  // Remove the first and empty element.
 844                  array_shift($steps);
 845              }
 846          
 847              // Start to evaluate the steps.
 848              $nodes = $this->evaluate_step($context, $steps);
 849          
 850              // Remove duplicated nodes.
 851              $nodes = array_unique($nodes);
 852              
 853              // Add the nodes to the result set.
 854              $result = array_merge($result, $nodes);
 855          }
 856          
 857          // Return the result.
 858          return $result;
 859      }
 860      
 861      /**
 862      * Handles opening XML tags while parsing.
 863      *
 864      * While parsing a XML document for each opening tag this method is
 865      * called. It'll add the tag found to the tree of document nodes.
 866      *
 867      * @access    private
 868      * @author    Michael P. Mehl <mpm@phpxml.org>
 869      * @param     int $parser Handler for accessing the current XML parser.
 870      * @param     string $name Name of the opening tag found in the document.
 871      * @param     array $attributes Associative array containing a list of
 872      *            all attributes of the tag found in the document.
 873      * @see       handle_end_element(), handle_character_data(), $nodes, $ids
 874      */
 875      function handle_start_element ( $parser, $name, $attributes )
 876      {
 877          // Add a node.
 878          $this->path = $this->add_node($this->path, $name);
 879          
 880          // Set the attributes.
 881          $this->set_attributes($this->path, $attributes);
 882      }
 883      
 884      /**
 885      * Handles closing XML tags while parsing.
 886      *
 887      * While parsing a XML document for each closing tag this method is
 888      * called.
 889      *
 890      * @access    private
 891      * @author    Michael P. Mehl <mpm@phpxml.org>
 892      * @param     int $parser Handler for accessing the current XML parser.
 893      * @param     string $name Name of the closing tag found in the document.
 894      * @see       handle_start_element(), handle_character_data(), $nodes, $ids
 895      */
 896      function handle_end_element ( $parser, $name )
 897      {
 898          // Jump back to the parent element.
 899          $this->path = substr($this->path, 0, strrpos($this->path, "/"));
 900      }
 901      
 902      /**
 903      * Handles character data while parsing.
 904      *
 905      * While parsing a XML document for each character data this method
 906      * is called. It'll add the character data to the document tree.
 907      *
 908      * @access    private
 909      * @author    Michael P. Mehl <mpm@phpxml.org>
 910      * @param     int $parser Handler for accessing the current XML parser.
 911      * @param     string $text Character data found in the document.
 912      * @see       handle_start_element(), handle_end_element(), $nodes, $ids
 913      */
 914      function handle_character_data ( $parser, $text )
 915      {
 916          // Replace entities.
 917          $text = strtr($text, $this->entities);
 918          
 919          // Save the text.
 920          $this->add_content($this->path, addslashes(trim($text)));
 921      }
 922      
 923      /**
 924      * Splits an XPath expression into its different expressions.
 925      *
 926      * This method splits an XPath expression. Each expression can consists of
 927      * list of expression being separated from each other by a | character.
 928      *
 929      * @access    private
 930      * @author    Michael P. Mehl <mpm@phpxml.org>
 931      * @param     string $expression The complete expression to be splitted
 932      *            into its different expressions.
 933      * @return    array The array returned from this method contains a list
 934      *            of all expressions found in the expression passed to this
 935      *            method as a parameter.
 936      * @see       evalute()
 937      */
 938      function split_paths ( $expression )
 939      {
 940          // Create an empty array.
 941          $paths = array();
 942          
 943          // Save the position of the slash.
 944          $position = -1;
 945          
 946          // Run through the expression.
 947          do
 948          {
 949              // Search for a slash.
 950              $position = $this->search_string($expression, "|");
 951              
 952              // Check whether a | was found.
 953              if ( $position >= 0 )
 954              {
 955                  // Get the left part of the expression.
 956                  $left  = substr($expression, 0, $position);
 957                  $right = substr($expression, $position + 1);
 958                  
 959                  // Add the left value to the steps.
 960                  $paths[] = $left;
 961                  
 962                  // Reduce the expression to the right part.
 963                  $expression = $right;
 964              }
 965          }
 966          while ( $position > -1 );
 967          
 968          // Add the remaing expression to the list of steps.
 969          $paths[] = $expression;
 970          
 971          // Return the steps.
 972          return $paths;
 973      }
 974      
 975      /**
 976      * Splits an XPath expression into its different steps.
 977      *
 978      * This method splits an XPath expression. Each expression can consists of
 979      * list of steps being separated from each other by a / character.
 980      *
 981      * @access    private
 982      * @author    Michael P. Mehl <mpm@phpxml.org>
 983      * @param     string $expression The complete expression to be splitted
 984      *            into its different steps.
 985      * @return    array The array returned from this method contains a list
 986      *            of all steps found in the expression passed to this
 987      *            method as a parameter.
 988      * @see       evalute()
 989      */
 990      function split_steps ( $expression )
 991      {
 992          // Create an empty array.
 993          $steps = array();
 994          
 995          // Replace a double slashes, because they'll cause problems otherwise.
 996          $expression = str_replace("//@", "/descendant::*/@", $expression);
 997          $expression = str_replace("//", "/descendant::", $expression);
 998          
 999          // Save the position of the slash.
1000          $position = -1;
1001          
1002          // Run through the expression.
1003          do
1004          {
1005              // Search for a slash.
1006              $position = $this->search_string($expression, "/");
1007              
1008              // Check whether a slash was found.
1009              if ( $position >= 0 )
1010              {
1011                  // Get the left part of the expression.
1012                  $left  = substr($expression, 0, $position);
1013                  $right = substr($expression, $position + 1);
1014                  
1015                  // Add the left value to the steps.
1016                  $steps[] = $left;
1017                  
1018                  // Reduce the expression to the right part.
1019                  $expression = $right;
1020              }
1021          }
1022          while ( $position > -1 );
1023          
1024          // Add the remaing expression to the list of steps.
1025          $steps[] = $expression;
1026          
1027          // Return the steps.
1028          return $steps;
1029      }
1030      
1031      /**
1032      * Retrieves axis information from an XPath expression step.
1033      *
1034      * This method tries to extract the name of the axis and its node-test
1035      * from a given step of an XPath expression at a given node.
1036      *
1037      * @access    private
1038      * @author    Michael P. Mehl <mpm@phpxml.org>
1039      * @param     string $step String containing a step of an XPath expression.
1040      * @param     string $node Full document path of the node on which the
1041      *            step is executed.
1042      * @return    array This method returns an array containing information
1043      *            about the axis found in the step.
1044      * @see       evaluate_step()
1045      */
1046      function get_axis ( $step, $node )
1047      {
1048          // Create an array to save the axis information.
1049          $axis = array(
1050              "axis"      => "",
1051              "node-test" => "",
1052              "predicate" => array()
1053          );
1054          
1055          // Check whether there are predicates.
1056          if ( ereg("\[", $step) )
1057          {
1058              // Get the predicates.
1059              $predicates = substr($step, strpos($step, "["));
1060              
1061              // Reduce the step.
1062              $step = $this->prestr($step, "[");
1063              
1064              // Try to split the predicates.
1065              $predicates = str_replace("][", "]|[", $predicates);
1066              $predicates = explode("|", $predicates);
1067              
1068              // Run through all predicates.
1069              foreach ( $predicates as $predicate )
1070              {
1071                  // Remove the brackets.
1072                  $predicate = substr($predicate, 1, strlen($predicate) - 2);
1073                  
1074                  // Add the predicate to the list of predicates.
1075                  $axis["predicate"][] = $predicate;
1076              }
1077          }
1078          
1079          // Check whether the axis is given in plain text.
1080          if ( $this->search_string($step, "::") > -1 )
1081          {
1082              // Split the step to extract axis and node-test.
1083              $axis["axis"]      = $this->prestr($step, "::");
1084              $axis["node-test"] = $this->afterstr($step, "::");
1085          }
1086          else
1087          {
1088              // Check whether the step is empty.
1089              if ( empty($step) )
1090              {
1091                  // Set it to the default value.
1092                  $step = ".";
1093              }
1094              
1095              // Check whether is an abbreviated syntax.
1096              if ( $step == "*" )
1097              {
1098                  // Use the child axis and select all children.
1099                  $axis["axis"]      = "child";
1100                  $axis["node-test"] = "*";
1101              }
1102              elseif ( ereg("\(", $step) )
1103              {
1104                  // Check whether it's a function.
1105                  if ( $this->is_function($this->prestr($step, "(")) )
1106                  {
1107                      // Get the position of the first bracket.
1108                      $start = strpos($step, "(");
1109                      $end   = strpos($step, ")", $start);
1110                      
1111                      // Get everything before, between and after the brackets.
1112                      $before  = substr($step, 0, $start);
1113                      $between = substr($step, $start + 1, $end - $start - 1);
1114                      $after   = substr($step, $end + 1);
1115                      
1116                      // Trim each string.
1117                      $before  = trim($before);
1118                      $between = trim($between);
1119                      $after   = trim($after);
1120                      
1121                      // Save the evaluated function.
1122                      $axis["axis"]      = "function";
1123                      $axis["node-test"] = $this->evaluate_function($before,
1124                          $between, $node);
1125                  }
1126                  else
1127                  {
1128                      // Use the child axis and a function.
1129                      $axis["axis"]      = "child";
1130                      $axis["node-test"] = $step;
1131                  }
1132              }
1133              elseif ( eregi("^@", $step) )
1134              {
1135                  // Use the attribute axis and select the attribute.
1136                  $axis["axis"]      = "attribute";
1137                  $axis["node-test"] = substr($step, 1);
1138              }
1139              elseif ( eregi("\]$", $step) )
1140              {
1141                  // Use the child axis and select a position.
1142                  $axis["axis"]      = "child";
1143                  $axis["node-test"] = substr($step, strpos($step, "["));
1144              }
1145              elseif ( $step == "." )
1146              {
1147                  // Select the self axis.
1148                  $axis["axis"]      = "self";
1149                  $axis["node-test"] = "*";
1150              }
1151              elseif ( $step == ".." )
1152              {
1153                  // Select the parent axis.
1154                  $axis["axis"]      = "parent";
1155                  $axis["node-test"] = "*";
1156              }
1157              elseif ( ereg("^[a-zA-Z0-9\-_]+$", $step) )
1158              {
1159                  // Select the child axis and the child.
1160                  $axis["axis"]      = "child";
1161                  $axis["node-test"] = $step;
1162              }
1163              else
1164              {
1165                  // Use the child axis and a name.
1166                  $axis["axis"]      = "child";
1167                  $axis["node-test"] = $step;
1168              }
1169          }
1170  
1171          // Check whether it's a valid axis.
1172          if ( !in_array($axis["axis"], array_merge($this->axes,
1173              array("function"))) )
1174          {
1175              // Display an error message.
1176              $this->display_error("While parsing an XPath expression, in ".
1177                  "the step \"%s\" the invalid axis \"%s\" was found.",
1178                  str_replace($step, "<b>".$step."</b>", $this->xpath),#
1179                  $axis["axis"]);  
1180          }
1181          
1182          // Return the axis information.
1183          return $axis;
1184      }
1185      
1186      /**
1187      * Looks for a string within another string.
1188      *
1189      * This method looks for a string within another string. Brackets in the
1190      * string the method is looking through will be respected, which means that
1191      * only if the string the method is looking for is located outside of
1192      * brackets, the search will be successful.
1193      *
1194      * @access    private
1195      * @author    Michael P. Mehl <mpm@phpxml.org>
1196      * @param     string $term String in which the search shall take place.
1197      * @param     string $expression String that should be searched.
1198      * @return    int This method returns -1 if no string was found, otherwise
1199      *            the offset at which the string was found.
1200      * @see       evaluate_step()
1201      */
1202      function search_string ( $term, $expression )
1203      {
1204          // Create a new counter for the brackets.
1205          $brackets = 0;
1206          
1207          // Run through the string.
1208          for ( $i = 0; $i < strlen($term); $i++ )
1209          {
1210              // Get the character at the position of the string.
1211              $character = substr($term, $i, 1);
1212              
1213              // Check whether it's a breacket.
1214              if ( ( $character == "(" ) || ( $character == "[" ) )
1215              {
1216                  // Increase the number of brackets.
1217                  $brackets++;
1218              }
1219              elseif ( ( $character == ")" ) || ( $character == "]" ) )
1220              {
1221                  // Decrease the number of brackets.
1222                  $brackets--;
1223              }
1224              elseif ( $brackets == 0 )
1225              {
1226                  // Check whether we can find the expression at this index.
1227                  if ( substr($term, $i, strlen($expression)) == $expression )
1228                  {
1229                      // Return the current index.
1230                      return $i;
1231                  }
1232              }
1233          }
1234          
1235          // Check whether we had a valid number of brackets.
1236          if ( $brackets != 0 )
1237          {
1238              // Display an error message.
1239              $this->display_error("While parsing an XPath expression, in the ".
1240                  "predicate \"%s\", there was an invalid number of brackets.",
1241                  str_replace($term, "<b>".$term."</b>", $this->xpath));
1242          }
1243  
1244          // Nothing was found.
1245          return (-1);
1246      }
1247      
1248      /**
1249      * Checks for a valid function name.
1250      *
1251      * This method check whether an expression contains a valid name of an
1252      * XPath function.
1253      *
1254      * @access    private
1255      * @author    Michael P. Mehl <mpm@phpxml.org>
1256      * @param     string $expression Name of the function to be checked.
1257      * @return    boolean This method returns true if the given name is a valid
1258      *            XPath function name, otherwise false.
1259      * @see       evaluate()
1260      */
1261      function is_function ( $expression )
1262      {
1263          // Check whether it's in the list of supported functions.
1264          if ( in_array($expression, $this->functions) )
1265          {
1266              // It's a function.
1267              return true;
1268          }
1269          else
1270          {
1271              // It's not a function.
1272              return false;
1273          }
1274      }
1275      
1276      /**
1277      * Evaluates a step of an XPath expression.
1278      *
1279      * This method tries to evaluate a step from an XPath expression at a
1280      * specific context.
1281      *
1282      * @access    private
1283      * @author    Michael P. Mehl <mpm@phpxml.org>
1284      * @param     string $context Full document path of the context from
1285      *            which starting the step should be evaluated.
1286      * @param     array $steps Array containing the remaining steps of the
1287      *            current XPath expression.
1288      * @return    array This method returns an array containing all nodes
1289      *            that are the result of evaluating the given XPath step.
1290      * @see       evaluate()
1291      */
1292      function evaluate_step ( $context, $steps )
1293      {
1294          // Create an empty array for saving the nodes found.
1295          $nodes = array();
1296  
1297          // Check whether the context is an array of contexts.
1298          if ( is_array($context) )
1299          {
1300              // Run through the array.
1301              foreach ( $context as $path )
1302              {
1303                  // Call this method for this single path.
1304                  $nodes = array_merge($nodes,
1305                      $this->evaluate_step($path, $steps));
1306              }
1307          }
1308          else
1309          {
1310              // Get this step.
1311              $step = array_shift($steps);
1312              
1313              // Create an array to save the new contexts.
1314              $contexts = array();
1315              
1316              // Get the axis of the current step.
1317              $axis = $this->get_axis($step, $context);
1318              
1319              // Check whether it's a function.
1320              if ( $axis["axis"] == "function" )
1321              {
1322                  // Check whether an array was return by the function.
1323                  if ( is_array($axis["node-test"]) )
1324                  {
1325                      // Add the results to the list of contexts.
1326                      $contexts = array_merge($contexts, $axis["node-test"]);
1327                  }
1328                  else
1329                  {
1330                      // Add the result to the list of contexts.
1331                      $contexts[] = $axis["node-test"];
1332                  }
1333              }
1334              else
1335              {
1336                  // Create the name of the method.
1337                  $method = "handle_axis_".str_replace("-", "_", $axis["axis"]);
1338              
1339                  // Check whether the axis handler is defined.
1340                  if ( !method_exists(&$this, $method) )
1341                  {
1342                      // Display an error message.
1343                      $this->display_error("While parsing an XPath expression, ".
1344                          "the axis \"%s\" could not be handled, because this ".
1345                          "version does not support this axis.", $axis["axis"]);
1346                  }
1347              
1348                  // Perform an axis action.
1349                  $contexts = call_user_method($method, &$this, $axis, $context);
1350              
1351                  // Check whether there are predicates.
1352                  if ( count($axis["predicate"]) > 0 )
1353                  {
1354                      // Check whether each node fits the predicates.
1355                      $contexts = $this->check_predicates($contexts,
1356                          $axis["predicate"]);
1357                  }
1358              }
1359              
1360              // Check whether there are more steps left.
1361              if ( count($steps) > 0 )
1362              {
1363                  // Continue the evaluation of the next steps.
1364                  $nodes = $this->evaluate_step($contexts, $steps);
1365              }
1366              else
1367              {
1368                  // Save the found contexts.
1369                  $nodes = $contexts;
1370              }
1371          }
1372          
1373          // Return the nodes found.
1374          return $nodes;
1375      }
1376      
1377      /**
1378      * Evaluates an XPath function
1379      *
1380      * This method evaluates a given XPath function with its arguments on a
1381      * specific node of the document.
1382      *
1383      * @access    private
1384      * @author    Michael P. Mehl <mpm@phpxml.org>
1385      * @param     string $function Name of the function to be evaluated.
1386      * @param     string $arguments String containing the arguments being
1387      *            passed to the function.
1388      * @param     string $node Full path to the document node on which the
1389      *            function should be evaluated.
1390      * @return    mixed This method returns the result of the evaluation of
1391      *            the function. Depending on the function the type of the 
1392      *            return value can be different.
1393      * @see       evaluate()
1394      */
1395      function evaluate_function ( $function, $arguments, $node )
1396      {
1397          // Remove whitespaces.
1398          $function  = trim($function);
1399          $arguments = trim($arguments);
1400  
1401          // Create the name of the function handling function.
1402          $method = "handle_function_".str_replace("-", "_", $function);
1403          
1404          // Check whether the function handling function is available.
1405          if ( !method_exists(&$this, $method) )
1406          {
1407              // Display an error message.
1408              $this->display_error("While parsing an XPath expression, ".
1409                  "the function \"%s\" could not be handled, because this ".
1410                  "version does not support this function.", $function);
1411          }
1412          
1413          // Return the result of the function.
1414          return call_user_method($method, &$this, $node, $arguments);
1415      }
1416      
1417      /**
1418      * Evaluates a predicate on a node.
1419      *
1420      * This method tries to evaluate a predicate on a given node.
1421      *
1422      * @access    private
1423      * @author    Michael P. Mehl <mpm@phpxml.org>
1424      * @param     string $node Full path of the node on which the predicate
1425      *            should be evaluated.
1426      * @param     string $predicate String containing the predicate expression
1427      *            to be evaluated.
1428      * @return    mixed This method is called recursively. The first call should
1429      *            return a boolean value, whether the node matches the predicate
1430      *            or not. Any call to the method being made during the recursion
1431      *            may also return other types for further processing.
1432      * @see       evaluate()
1433      */
1434      function evaluate_predicate ( $node, $predicate )
1435      {
1436          // Set the default position and the type of the operator.
1437          $position = 0;
1438          $operator = "";
1439          
1440          // Run through all operators and try to find them.
1441          foreach ( $this->operators as $expression )
1442          {
1443              // Check whether a position was already found.
1444              if ( $position <= 0 )
1445              {
1446                  // Try to find the operator.
1447                  $position = $this->search_string($predicate, $expression);
1448              
1449                  // Check whether a operator was found.
1450                  if ( $position > 0 )
1451                  {
1452                      // Save the operator.
1453                      $operator = $expression;
1454                      
1455                      // Check whether it's the equal operator.
1456                      if ( $operator == "=" )
1457                      {
1458                          // Also look for other operators containing the
1459                          // equal sign.
1460                          if ( $this->search_string($predicate, "!=") ==
1461                              ( $position - 1 ) )
1462                          {
1463                              // Get the new position.
1464                              $position = $this->search_string($predicate, "!=");
1465                              
1466                              // Save the new operator.
1467                              $operator = "!=";
1468                          }
1469                          if ( $this->search_string($predicate, "<=") ==
1470                              ( $position - 1 ) )
1471                          {
1472                              // Get the new position.
1473                              $position = $this->search_string($predicate, "<=");
1474                              
1475                              // Save the new operator.
1476                              $operator = "<=";
1477                          }
1478                          if ( $this->search_string($predicate, ">=") ==
1479                              ( $position - 1 ) )
1480                          {
1481                              // Get the new position.
1482                              $position = $this->search_string($predicate, ">=");
1483                              
1484                              // Save the new operator.
1485                              $operator = ">=";
1486                          }
1487                      }
1488                  }
1489              }
1490          }
1491          
1492          // Check whether the operator is a - sign.
1493          if ( $operator == "-" )
1494          {
1495              // Check whether it's not a function containing a - in its name.
1496              foreach ( $this->functions as $function )
1497              {
1498                  // Check whether there's a - sign in the function name.
1499                  if ( ereg("-", $function) )
1500                  {
1501                      // Get the position of the - in the function name.
1502                      $sign = strpos($function, "-");
1503                      
1504                      // Extract a substring from the predicate.
1505                      $sub = substr($predicate, $position - $sign,
1506                          strlen($function));
1507                          
1508                      // Check whether it's the function.
1509                      if ( $sub == $function )
1510                      {
1511                          // Don't use the operator.
1512                          $operator = "";
1513                          $position = -1;
1514                      }
1515                  }
1516              }
1517          }
1518          elseif ( $operator == "*" )
1519          {
1520              // Get some substrings.
1521              $character = substr($predicate, $position - 1, 1);
1522              $attribute = substr($predicate, $position - 11, 11);
1523              
1524              // Check whether it's an attribute selection.
1525              if ( ( $character == "@" ) || ( $attribute == "attribute::" ) )
1526              {
1527                  // Don't use the operator.
1528                  $operator = "";
1529                  $position = -1;
1530              }
1531          }
1532          
1533          // Check whether an operator was found.        
1534          if ( $position > 0 )
1535          {
1536              // Get the left and the right part of the expression.
1537              $left  = substr($predicate, 0, $position);
1538              $right = substr($predicate, $position + strlen($operator));
1539              
1540              // Remove whitespaces.
1541              $left  = trim($left);
1542              $right = trim($right);
1543              
1544              // Evaluate the left and the right part.
1545              $left  = $this->evaluate_predicate($node, $left);
1546              $right = $this->evaluate_predicate($node, $right);
1547              
1548              // Check the kind of operator.
1549              switch ( $operator )
1550              {
1551                  case " or ":
1552                      // Return the two results connected by an "or".
1553                      return ( $left or $right );
1554                  
1555                  case " and ":
1556                      // Return the two results connected by an "and".
1557                      return ( $left and $right );
1558                  
1559                  case "=":
1560                      // Compare the two results.
1561                      return ( $left == $right );
1562                      
1563                  case "!=":
1564                      // Check whether the two results are not equal.
1565                      return ( $left != $right );
1566                      
1567                  case "<=":
1568                      // Compare the two results.
1569                      return ( $left <= $right );
1570                      
1571                  case "<":
1572                      // Compare the two results.
1573                      return ( $left < $right );
1574                  
1575                  case ">=":
1576                      // Compare the two results.
1577                      return ( $left >= $right );
1578                      
1579                  case ">":
1580                      // Compare the two results.
1581                      return ( $left > $right );
1582                      
1583                  case "+":
1584                      // Return the result by adding one result to the other.
1585                      return ( $left + $right );
1586                  
1587                  case "-":
1588                      // Return the result by decrease one result by the other.
1589                      return ( $left - $right );
1590                  
1591                  case "*":
1592                      // Return a multiplication of the two results.
1593                      return ( $left * $right );
1594                      
1595                  case " div ":
1596                      // Return a division of the two results.
1597                      if ( $right == 0 )
1598                      {
1599                          // Display an error message.
1600                          $this->display_error("While parsing an XPath ".
1601                              "predicate, a error due a division by zero ".
1602                              "occured.");
1603                      }
1604                      else
1605                      {
1606                          // Return the result of the division.
1607                          return ( $left / $right );
1608                      }
1609                      break;
1610                  
1611                  case " mod ":
1612                      // Return a modulo of the two results.
1613                      return ( $left % $right );
1614              }
1615          }
1616          
1617          // Check whether the predicate is a function.
1618          if ( ereg("\(", $predicate) )
1619          {
1620              // Get the position of the first bracket.
1621              $start = strpos($predicate, "(");
1622              $end   = strpos($predicate, ")", $start);
1623              
1624              // Get everything before, between and after the brackets.
1625              $before  = substr($predicate, 0, $start);
1626              $between = substr($predicate, $start + 1, $end - $start - 1);
1627              $after   = substr($predicate, $end + 1);
1628              
1629              // Trim each string.
1630              $before  = trim($before);
1631              $between = trim($between);
1632              $after   = trim($after);
1633              
1634              // Check whether there's something after the bracket.
1635              if ( !empty($after) )
1636              {
1637                  // Display an error message.
1638                  $this->display_error("While parsing an XPath expression ".
1639                      "there was found an error in the predicate \"%s\", ".
1640                      "because after a closing bracket there was found ".
1641                      "something unknown.", str_replace($predicate,
1642                      "<b>".$predicate."</b>", $this->xpath));
1643              }
1644              
1645              // Check whether it's a function.
1646              if ( empty($before) && empty($after) )
1647              {
1648                  // Evaluate the content of the brackets.
1649                  return $this->evaluate_predicate($node, $between);
1650              }
1651              elseif ( $this->is_function($before) )
1652              {
1653                  // Return the evaluated function.
1654                  return $this->evaluate_function($before, $between, $node);
1655              }
1656              else
1657              {
1658                  // Display an error message.
1659                  $this->display_error("While parsing a predicate in an XPath ".
1660                      "expression, a function \"%s\" was found, which is not ".
1661                      "yet supported by the parser.", str_replace($before,
1662                      "<b>".$before."</b>", $this->xpath));
1663              }
1664          }
1665          
1666          // Check whether the predicate is just a digit.
1667          if ( ereg("^[0-9]+(\.[0-9]+)?$", $predicate) ||
1668              ereg("^\.[0-9]+$", $predicate) )
1669          {
1670              // Return the value of the digit.
1671              return doubleval($predicate);
1672          }
1673          
1674          // Check whether it's an XPath expression.
1675          $result = $this->evaluate($predicate, $node);
1676          if ( count($result) > 0 )
1677          {
1678              // Convert the array.
1679              $result = explode("|", implode("|", $result));
1680              
1681              // Get the value of the first result.
1682              $value = $this->get_content($result[0]);
1683              
1684              // Return the value.
1685              return $value;
1686          }
1687          
1688          // Return the predicate as a string.
1689          return $predicate;
1690      }
1691      
1692      /**
1693      * Checks whether a node matches predicates.
1694      *
1695      * This method checks whether a list of nodes passed to this method match
1696      * a given list of predicates. 
1697      *
1698      * @access    private
1699      * @author    Michael P. Mehl <mpm@phpxml.org>
1700      * @param     array $nodes Array of full paths of all nodes to be tested.
1701      * @param     array $predicates Array of predicates to use.
1702      * @return    array The array returned by this method contains a list of
1703      *            all nodes matching the given predicates.
1704      * @see       evaluate_step()
1705      */
1706      function check_predicates ( $nodes, $predicates )
1707      {
1708          // Create an empty set of nodes.
1709          $result = array();
1710          
1711          // Run through all nodes.
1712          foreach ( $nodes as $node )
1713          {
1714              // Create a variable whether to add this node to the node-set.
1715              $add = true;
1716              
1717              // Run through all predicates.
1718              foreach ( $predicates as $predicate )
1719              {
1720                  // Check whether the predicate is just an number.
1721                  if ( ereg("^[0-9]+$", $predicate) )
1722                  {
1723                      // Enhance the predicate.
1724                      $predicate .= "=position()";
1725                  }
1726                  
1727                  // Do the predicate check.
1728                  $check = $this->evaluate_predicate($node, $predicate);
1729                  
1730                  // Check whether it's a string.
1731                  if ( is_string($check) && ( ( $check == "" ) ||
1732                      ( $check == $predicate ) ) )
1733                  {
1734                      // Set the result to false.
1735                      $check = false;
1736                  }
1737                  
1738                  // Check whether it's an integer.
1739                  if ( is_int($check) )
1740                  {
1741                      // Check whether it's the current position.
1742                      if ( $check == $this->handle_function_position($node, "") )
1743                      {
1744                          // Set it to true.
1745                          $check = true;
1746                      }
1747                      else
1748                      {
1749                          // Set it to false.
1750                          $check = false;
1751                      }
1752                  }
1753                  
1754                  // Check whether the predicate is OK for this node.
1755                  $add = $add && $check;
1756              }
1757              
1758              // Check whether to add this node to the node-set.
1759              if ( $add )
1760              {
1761                  // Add the node to the node-set.
1762                  $result[] = $node;
1763              }            
1764          }
1765          
1766          // Return the array of nodes.
1767          return $result;
1768      }
1769      
1770      /**
1771      * Checks whether a node matches a node-test.
1772      *
1773      * This method checks whether a node in the document matches a given
1774      * node-test.
1775      *
1776      * @access    private
1777      * @author    Michael P. Mehl <mpm@phpxml.org>
1778      * @param     string $context Full path of the node, which should be tested
1779      *            for matching the node-test.
1780      * @param     string $node_test String containing the node-test for the
1781      *            node.
1782      * @return    boolean This method returns true if the node matches the
1783      *            node-test, otherwise false.
1784      * @see       evaluate()
1785      */
1786      function check_node_test ( $context, $node_test )
1787      {
1788          // Check whether it's a function.
1789          if ( ereg("\(", $node_test) )
1790          {
1791              // Get the type of function to use.
1792              $function = $this->prestr($node_test, "(");
1793              
1794              // Check whether the node fits the method.
1795              switch ( $function )
1796              {
1797                  case "node":
1798                      // Add this node to the list of nodes.
1799                      return true;
1800                      
1801                  case "text":
1802                      // Check whether the node has some text.
1803                      if ( !empty($this->nodes[$context]["text"]) )
1804                      {
1805                          // Add this node to the list of nodes.
1806                          return true;
1807                      }
1808                      break;
1809                      
1810                  case "comment":
1811                      // Check whether the node has some comment.
1812                      if ( !empty($this->nodes[$context]["comment"]) )
1813                      {
1814                          // Add this node to the list of nodes.
1815                          return true;
1816                      }
1817                      break;
1818                  
1819                  case "processing-instruction":
1820                      // Get the literal argument.
1821                      $literal = $this->afterstr($axis["node-test"], "(");
1822                      
1823                      // Cut the literal.
1824                      $literal = substr($literal, 0, strlen($literal) - 1);
1825                      
1826                      // Check whether a literal was given.
1827                      if ( !empty($literal) )
1828                      {
1829                          // Check whether the node's processing instructions
1830                          // are matching the literals given.
1831                          if ( $this->nodes[$context]
1832                              ["processing-instructions"] == $literal )
1833                          {
1834                              // Add this node to the node-set.
1835                              return true;
1836                          }
1837                      }
1838                      else
1839                      {
1840                          // Check whether the node has processing
1841                          // instructions.
1842                          if ( !empty($this->nodes[$context]
1843                              ["processing-instructions"]) )
1844                          {
1845                              // Add this node to the node-set.
1846                              return true;
1847                          }
1848                      }
1849                      break;
1850                      
1851                  default:
1852                      // Display an error message.
1853                      $this->display_error("While parsing an XPath ".
1854                          "expression there was found an undefined ".
1855                          "function called \"%s\".",
1856                          str_replace($function, "<b>".$function."</b>",
1857                          $this->xpath));
1858              }
1859          }
1860          elseif ( $node_test == "*" )
1861          {
1862              // Add this node to the node-set.
1863              return true;
1864          }
1865          elseif ( ereg("^[a-zA-Z0-9\-_]+", $node_test) )
1866          {
1867              // Check whether the node-test can be fulfilled.
1868              if ( $this->nodes[$context]["name"] == $node_test )
1869              {
1870                  // Add this node to the node-set.
1871                  return true;
1872              }
1873          }
1874          else
1875          {
1876              // Display an error message.
1877              $this->display_error("While parsing the XPath expression \"%s\" ".
1878                  "an empty and therefore invalid node-test has been found.",
1879                  $this->xpath);
1880          }
1881          
1882          // Don't add this context.
1883          return false;
1884      }
1885      
1886      /**
1887      * Handles the XPath child axis.
1888      *
1889      * This method handles the XPath child axis.
1890      *
1891      * @access    private
1892      * @author    Michael P. Mehl <mpm@phpxml.org>
1893      * @param     array $axis Array containing information about the axis.
1894      * @param     string $context Node from which starting the axis should
1895      *            be processed.
1896      * @return    array This method returns an array containing all nodes 
1897      *            that were found during the evaluation of the given axis.
1898      * @see       evaluate()
1899      */
1900      function handle_axis_child ( $axis, $context )
1901      {
1902          // Create an empty node-set.
1903          $nodes = array();
1904          
1905          // Get a list of all children.
1906          $children = $this->nodes[$context]["children"];
1907          
1908          // Check whether there are children.
1909          if ( !empty($children) )
1910          {
1911              // Run through all children.
1912              foreach ( $children as $child_name => $child_position )
1913              {
1914                  // Run through all childs with this name.
1915                  for ( $i = 1; $i <= $child_position; $i++ )
1916                  {
1917                      // Create the path of the child.
1918                      $child = $context."/".$child_name."[".$i."]";
1919                      
1920                      // Check whether 
1921                      if ( $this->check_node_test($child, $axis["node-test"]) )
1922                      {
1923                          // Add the child to the node-set.
1924                          $nodes[] = $child;
1925                      }
1926                  }
1927              }
1928          }
1929          
1930          // Return the nodeset.
1931          return $nodes;
1932      }
1933      
1934      /**
1935      * Handles the XPath parent axis.
1936      *
1937      * This method handles the XPath parent axis.
1938      *
1939      * @access    private
1940      * @author    Michael P. Mehl <mpm@phpxml.org>
1941      * @param     array $axis Array containing information about the axis.
1942      * @param     string $context Node from which starting the axis should
1943      *            be processed.
1944      * @return    array This method returns an array containing all nodes 
1945      *            that were found during the evaluation of the given axis.
1946      * @see       evaluate()
1947      */
1948      function handle_axis_parent ( $axis, $context )
1949      {
1950          // Create an empty node-set.
1951          $nodes = array();
1952          
1953          // Check whether the parent matches the node-test.
1954          if ( $this->check_node_test($this->nodes[$context]["parent"],
1955              $axis["node-test"]) )
1956          {
1957              // Add this node to the list of nodes.
1958              $nodes[] = $this->nodes[$context]["parent"];
1959          }
1960          
1961          // Return the nodeset.
1962          return $nodes;
1963      }
1964      
1965      /**
1966      * Handles the XPath attribute axis.
1967      *
1968      * This method handles the XPath attribute axis.
1969      *
1970      * @access    private
1971      * @author    Michael P. Mehl <mpm@phpxml.org>
1972      * @param     array $axis Array containing information about the axis.
1973      * @param     string $context Node from which starting the axis should
1974      *            be processed.
1975      * @return    array This method returns an array containing all nodes 
1976      *            that were found during the evaluation of the given axis.
1977      * @see       evaluate()
1978      */
1979      function handle_axis_attribute ( $axis, $context )
1980      {
1981          // Create an empty node-set.
1982          $nodes = array();
1983          
1984          // Check whether all nodes should be selected.
1985          if ( $axis["node-test"] == "*" )
1986          {
1987              // Check whether there are attributes.
1988              if ( count($this->nodes[$context]["attributes"]) > 0 )
1989              {
1990                  // Run through the attributes.
1991                  foreach ( $this->nodes[$context]["attributes"] as
1992                      $key => $value )
1993                  {
1994                      // Add this node to the node-set.
1995                      $nodes[] = $context."/attribute::".$key;
1996                  }
1997              }
1998          }
1999          elseif ( !empty($this->nodes[$context]["attributes"]
2000              [$axis["node-test"]]) )
2001          {
2002              // Add this node to the node-set.
2003              $nodes[] = $context."/attribute::".$axis["node-test"];
2004          }
2005              
2006          // Return the nodeset.
2007          return $nodes;
2008      }
2009  
2010      /**
2011      * Handles the XPath self axis.
2012      *
2013      * This method handles the XPath self axis.
2014      *
2015      * @access    private
2016      * @author    Michael P. Mehl <mpm@phpxml.org>
2017      * @param     array $axis Array containing information about the axis.
2018      * @param     string $context Node from which starting the axis should
2019      *            be processed.
2020      * @return    array This method returns an array containing all nodes 
2021      *            that were found during the evaluation of the given axis.
2022      * @see       evaluate()
2023      */
2024      function handle_axis_self ( $axis, $context )
2025      {
2026          // Create an empty node-set.
2027          $nodes = array();
2028          
2029          // Check whether the context match the node-test.
2030          if ( $this->check_node_test($context, $axis["node-test"]) )
2031          {
2032              // Add this node to the node-set.
2033              $nodes[] = $context;
2034          }
2035  
2036          // Return the nodeset.
2037          return $nodes;
2038      }
2039  
2040      /**
2041      * Handles the XPath descendant axis.
2042      *
2043      * This method handles the XPath descendant axis.
2044      *
2045      * @access    private
2046      * @author    Michael P. Mehl <mpm@phpxml.org>
2047      * @param     array $axis Array containing information about the axis.
2048      * @param     string $context Node from which starting the axis should
2049      *            be processed.
2050      * @return    array This method returns an array containing all nodes 
2051      *            that were found during the evaluation of the given axis.
2052      * @see       evaluate()
2053      */
2054      function handle_axis_descendant ( $axis, $context )
2055      {
2056          // Create an empty node-set.
2057          $nodes = array();
2058          
2059          // Check whether the current node has children.
2060          if ( count($this->nodes[$context]["children"]) > 0 )
2061          {
2062              // Get a list of children.
2063              $children = $this->nodes[$context]["children"];
2064              
2065              // Run through all children.
2066              foreach ( $children as $child_name => $child_position )
2067              {
2068                  // Run through all children of this name.
2069                  for ( $i = 1; $i <= $child_position; $i++ )
2070                  {
2071                      // Create the full path for the children.
2072                      $child = $context."/".$child_name."[".$i."]";
2073                      
2074                      // Check whether the child matches the node-test.
2075                      if ( $this->check_node_test($child, $axis["node-test"]) )
2076                      {
2077                          // Add the child to the list of nodes.
2078                          $nodes[] = $child;
2079                      }
2080                      
2081                      // Recurse to the next level.
2082                      $nodes = array_merge($nodes,
2083                          $this->handle_axis_descendant($axis, $child));
2084                  }
2085              }
2086          }
2087          
2088          // Return the nodeset.
2089          return $nodes;
2090      }
2091  
2092      /**
2093      * Handles the XPath ancestor axis.
2094      *
2095      * This method handles the XPath ancestor axis.
2096      *
2097      * @access    private
2098      * @author    Michael P. Mehl <mpm@phpxml.org>
2099      * @param     array $axis Array containing information about the axis.
2100      * @param     string $context Node from which starting the axis should
2101      *            be processed.
2102      * @return    array This method returns an array containing all nodes 
2103      *            that were found during the evaluation of the given axis.
2104      * @see       evaluate()
2105      */
2106      function handle_axis_ancestor ( $axis, $context )
2107      {
2108          // Create an empty node-set.
2109          $nodes = array();
2110          
2111          // Get the parent of the current node.
2112          $parent = $this->nodes[$context]["parent"];
2113          
2114          // Check whether the parent isn't empty.
2115          if ( !empty($parent) )
2116          {
2117              // Check whether the parent matches the node-test.
2118              if ( $this->check_node_test($parent, $axis["node-test"]) )
2119              {
2120                  // Add the parent to the list of nodes.
2121                  $nodes[] = $parent;
2122              }
2123              
2124              // Handle all other ancestors.
2125              $nodes = array_merge($nodes,
2126                  $this->handle_axis_ancestor($axis, $parent));
2127          }
2128          
2129          // Return the nodeset.
2130          return $nodes;
2131      }
2132  
2133      /**
2134      * Handles the XPath namespace axis.
2135      *
2136      * This method handles the XPath namespace axis.
2137      *
2138      * @access    private
2139      * @author    Michael P. Mehl <mpm@phpxml.org>
2140      * @param     array $axis Array containing information about the axis.
2141      * @param     string $context Node from which starting the axis should
2142      *            be processed.
2143      * @return    array This method returns an array containing all nodes 
2144      *            that were found during the evaluation of the given axis.
2145      * @see       evaluate()
2146      */
2147      function handle_axis_namespace ( $axis, $context )
2148      {
2149          // Create an empty node-set.
2150          $nodes = array();
2151          
2152          // Check whether all nodes should be selected.
2153          if ( !empty($this->nodes[$context]["namespace"]) )
2154          {
2155              // Add this node to the node-set.
2156              $nodes[] = $context;
2157          }
2158              
2159          // Return the nodeset.
2160          return $nodes;
2161      }
2162      
2163      /**
2164      * Handles the XPath following axis.
2165      *
2166      * This method handles the XPath following axis.
2167      *
2168      * @access    private
2169      * @author    Michael P. Mehl <mpm@phpxml.org>
2170      * @param     array $axis Array containing information about the axis.
2171      * @param     string $context Node from which starting the axis should
2172      *            be processed.
2173      * @return    array This method returns an array containing all nodes 
2174      *            that were found during the evaluation of the given axis.
2175      * @see       evaluate()
2176      */
2177      function handle_axis_following ( $axis, $context )
2178      {
2179          // Create an empty node-set.
2180          $nodes = array();
2181          
2182          // Get the current document position.
2183          $position = $this->nodes[$context]["document-position"];
2184          
2185          // Create a flag, whether we already found the context node.
2186          $found = false;
2187          
2188          // Run through all nodes of the document.
2189          foreach ( $this->nodes as $node => $data )
2190          {
2191              // Check whether the context node has already been found.
2192              if ( $found )
2193              {
2194                  // Check whether the position is correct.
2195                  if ( $this->nodes[$node]["document-position"] == $position )
2196                  {
2197                      // Check whether the node fits the node-test.
2198                      if ( $this->check_node_test($node, $axis["node-test"]) )
2199                      {
2200                          // Add the node to the list of nodes.
2201                          $nodes[] = $node;
2202                      }
2203                  }
2204              }
2205              
2206              // Check whether this is the context node.
2207              if ( $node == $context )
2208              {
2209                  // After this we'll look for more nodes.
2210                  $found = true;
2211              }
2212          }
2213              
2214          // Return the nodeset.
2215          return $nodes;
2216      }
2217      
2218      /**
2219      * Handles the XPath preceding axis.
2220      *
2221      * This method handles the XPath preceding axis.
2222      *
2223      * @access    private
2224      * @author    Michael P. Mehl <mpm@phpxml.org>
2225      * @param     array $axis Array containing information about the axis.
2226      * @param     string $context Node from which starting the axis should
2227      *            be processed.
2228      * @return    array This method returns an array containing all nodes 
2229      *            that were found during the evaluation of the given axis.
2230      * @see       evaluate()
2231      */
2232      function handle_axis_preceding ( $axis, $context )
2233      {
2234          // Create an empty node-set.
2235          $nodes = array();
2236          
2237          // Get the current document position.
2238          $position = $this->nodes[$context]["document-position"];
2239          
2240          // Create a flag, whether we already found the context node.
2241          $found = true;
2242          
2243          // Run through all nodes of the document.
2244          foreach ( $this->nodes as $node => $data )
2245          {
2246              // Check whether this is the context node.
2247              if ( $node == $context )
2248              {
2249                  // After this we won't look for more nodes.
2250                  $found = false;
2251              }
2252              
2253              // Check whether the context node has already been found.
2254              if ( $found )
2255              {
2256                  // Check whether the position is correct.
2257                  if ( $this->nodes[$node]["document-position"] == $position )
2258                  {
2259                      // Check whether the node fits the node-test.
2260                      if ( $this->check_node_test($node, $axis["node-test"]) )
2261                      {
2262                          // Add the node to the list of nodes.
2263                          $nodes[] = $node;
2264                      }
2265                  }
2266              }
2267          }
2268              
2269          // Return the nodeset.
2270          return $nodes;
2271      }
2272      
2273      /**
2274      * Handles the XPath following-sibling axis.
2275      *
2276      * This method handles the XPath following-sibling axis.
2277      *
2278      * @access    private
2279      * @author    Michael P. Mehl <mpm@phpxml.org>
2280      * @param     array $axis Array containing information about the axis.
2281      * @param     string $context Node from which starting the axis should
2282      *            be processed.
2283      * @return    array This method returns an array containing all nodes 
2284      *            that were found during the evaluation of the given axis.
2285      * @see       evaluate()
2286      */
2287      function handle_axis_following_sibling ( $axis, $context )
2288      {
2289          // Create an empty node-set.
2290          $nodes = array();
2291          
2292          // Get all children from the parent.
2293          $siblings = $this->handle_axis_child($axis,
2294              $this->nodes[$context]["parent"]);
2295          
2296          // Create a flag whether the context node was already found.
2297          $found = false;
2298          
2299          // Run through all siblings.
2300          foreach ( $siblings as $sibling )
2301          {
2302              // Check whether the context node was already found.
2303              if ( $found )
2304              {
2305                  // Check whether the sibling is a real sibling.
2306                  if ( $this->nodes[$sibling]["name"] ==
2307                      $this->nodes[$context]["name"] )
2308                  {
2309                      // Check whether the sibling matches the node-test.
2310                      if ( $this->check_node_test($sibling, $axis["node-test"]) )
2311                      {
2312                          // Add the sibling to the list of nodes.
2313                          $nodes[] = $sibling;
2314                      }
2315                  }
2316              }
2317              
2318              // Check whether this is the context node.
2319              if ( $sibling == $context )
2320              {
2321                  // Continue looking for other siblings.
2322                  $found = true;
2323              }
2324          }
2325              
2326          // Return the nodeset.
2327          return $nodes;
2328      }
2329      
2330      /**
2331      * Handles the XPath preceding-sibling axis.
2332      *
2333      * This method handles the XPath preceding-sibling axis.
2334      *
2335      * @access    private
2336      * @author    Michael P. Mehl <mpm@phpxml.org>
2337      * @param     array $axis Array containing information about the axis.
2338      * @param     string $context Node from which starting the axis should
2339      *            be processed.
2340      * @return    array This method returns an array containing all nodes 
2341      *            that were found during the evaluation of the given axis.
2342      * @see       evaluate()
2343      */
2344      function handle_axis_preceding_sibling ( $axis, $context )
2345      {
2346          // Create an empty node-set.
2347          $nodes = array();
2348          
2349          // Get all children from the parent.
2350          $siblings = $this->handle_axis_child($axis,
2351              $this->nodes[$context]["parent"]);
2352          
2353          // Create a flag whether the context node was already found.
2354          $found = true;
2355          
2356          // Run through all siblings.
2357          foreach ( $siblings as $sibling )
2358          {
2359              // Check whether this is the context node.
2360              if ( $sibling == $context )
2361              {
2362                  // Don't continue looking for other siblings.
2363                  $found = false;
2364              }
2365              
2366              // Check whether the context node was already found.
2367              if ( $found )
2368              {
2369                  // Check whether the sibling is a real sibling.
2370                  if ( $this->nodes[$sibling]["name"] ==
2371                      $this->nodes[$context]["name"] )
2372                  {
2373                      // Check whether the sibling matches the node-test.
2374                      if ( $this->check_node_test($sibling, $axis["node-test"]) )
2375                      {
2376                          // Add the sibling to the list of nodes.
2377                          $nodes[] = $sibling;
2378                      }
2379                  }
2380              }
2381          }
2382              
2383          // Return the nodeset.
2384          return $nodes;
2385      }
2386      
2387      /**
2388      * Handles the XPath descendant-or-self axis.
2389      *
2390      * This method handles the XPath descendant-or-self axis.
2391      *
2392      * @access    private
2393      * @author    Michael P. Mehl <mpm@phpxml.org>
2394      * @param     array $axis Array containing information about the axis.
2395      * @param     string $context Node from which starting the axis should
2396      *            be processed.
2397      * @return    array This method returns an array containing all nodes 
2398      *            that were found during the evaluation of the given axis.
2399      * @see       evaluate()
2400      */
2401      function handle_axis_descendant_or_self ( $axis, $context )
2402      {
2403          // Create an empty node-set.
2404          $nodes = array();
2405          
2406          // Read the nodes.
2407          $nodes = array_merge(
2408              $this->handle_axis_descendant($axis, $context),
2409              $this->handle_axis_self($axis, $context));
2410          
2411          // Return the nodeset.
2412          return $nodes;
2413      }
2414      
2415      /**
2416      * Handles the XPath ancestor-or-self axis.
2417      *
2418      * This method handles the XPath ancestor-or-self axis.
2419      *
2420      * @access    private
2421      * @author    Michael P. Mehl <mpm@phpxml.org>
2422      * @param     array $axis Array containing information about the axis.
2423      * @param     string $context Node from which starting the axis should
2424      *            be processed.
2425      * @return    array This method returns an array containing all nodes 
2426      *            that were found during the evaluation of the given axis.
2427      * @see       evaluate()
2428      */
2429      function handle_axis_ancestor_or_self ( $axis, $context )
2430      {
2431          // Create an empty node-set.
2432          $nodes = array();
2433          
2434          // Read the nodes.
2435          $nodes = array_merge(
2436              $this->handle_axis_ancestor($axis, $context),
2437              $this->handle_axis_self($axis, $context));
2438          
2439          // Return the nodeset.
2440          return $nodes;
2441      }
2442      
2443      /**
2444      * Handles the XPath function last.
2445      *
2446      * This method handles the XPath function last.
2447      *
2448      * @access    private
2449      * @author    Michael P. Mehl <mpm@phpxml.org>
2450      * @param     string $node Full path of the node on which the function
2451      *            should be processed.
2452      * @param     string $arguments String containing the arguments that were
2453      *            passed to the function.
2454      * @return    mixed Depending on the type of function being processed this 
2455      *            method returns different types.
2456      * @see       evaluate()
2457      */
2458      function handle_function_last ( $node, $arguments )
2459      {
2460          // Calculate the size of the context.
2461          $parent   = $this->nodes[$node]["parent"];
2462          $children = $this->nodes[$parent]["children"];
2463          $context  = $children[$this->nodes[$node]["name"]];
2464  
2465          // Return the size.
2466          return $context;
2467      }
2468  
2469      /**
2470      * Handles the XPath function position.
2471      *
2472      * This method handles the XPath function position.
2473      *
2474      * @access    private
2475      * @author    Michael P. Mehl <mpm@phpxml.org>
2476      * @param     string $node Full path of the node on which the function
2477      *            should be processed.
2478      * @param     string $arguments String containing the arguments that were
2479      *            passed to the function.
2480      * @return    mixed Depending on the type of function being processed this 
2481      *            method returns different types.
2482      * @see       evaluate()
2483      */
2484      function handle_function_position ( $node, $arguments )
2485      {
2486          // return the context-position.
2487          return $this->nodes[$node]["context-position"];
2488      }
2489      
2490      /**
2491      * Handles the XPath function count.
2492      *
2493      * This method handles the XPath function count.
2494      *
2495      * @access    private
2496      * @author    Michael P. Mehl <mpm@phpxml.org>
2497      * @param     string $node Full path of the node on which the function
2498      *            should be processed.
2499      * @param     string $arguments String containing the arguments that were
2500      *            passed to the function.
2501      * @return    mixed Depending on the type of function being processed this 
2502      *            method returns different types.
2503      * @see       evaluate()
2504      */
2505      function handle_function_count ( $node, $arguments )
2506      {
2507          // Evaluate the argument of the method as an XPath and return
2508          // the number of results.
2509          return count($this->evaluate($arguments, $node));
2510      }
2511      
2512      /**
2513      * Handles the XPath function id.
2514      *
2515      * This method handles the XPath function id.
2516      *
2517      * @access    private
2518      * @author    Michael P. Mehl <mpm@phpxml.org>
2519      * @param     string $node Full path of the node on which the function
2520      *            should be processed.
2521      * @param     string $arguments String containing the arguments that were
2522      *            passed to the function.
2523      * @return    mixed Depending on the type of function being processed this 
2524      *            method returns different types.
2525      * @see       evaluate()
2526      */
2527      function handle_function_id ( $node, $arguments )
2528      {
2529          // Trim the arguments.
2530          $arguments = trim($arguments);
2531          
2532          // Now split the arguments.
2533          $arguments = explode(" ", $arguments);
2534          
2535          // Check whether 
2536          
2537          // Create a list of nodes.
2538          $nodes = array();
2539          
2540          // Run through all document node.
2541          foreach ( $this->nodes as $node => $position )
2542          {
2543              // Check whether the node has the ID we're looking for.
2544              if ( in_array($this->nodes[$node]["attributes"]["id"],
2545                  $arguments) )
2546              {
2547                  // Add this node to the list of nodes.
2548                  $nodes[] = $node;
2549              }
2550          }
2551          
2552          // Return the list of nodes.
2553          return $nodes;
2554      }
2555      
2556      /**
2557      * Handles the XPath function name.
2558      *
2559      * This method handles the XPath function name.
2560      *
2561      * @access    private
2562      * @author    Michael P. Mehl <mpm@phpxml.org>
2563      * @param     string $node Full path of the node on which the function
2564      *            should be processed.
2565      * @param     string $arguments String containing the arguments that were
2566      *            passed to the function.
2567      * @return    mixed Depending on the type of function being processed this 
2568      *            method returns different types.
2569      * @see       evaluate()
2570      */
2571      function handle_function_name ( $node, $arguments )
2572      {
2573          // Return the name of the node.
2574          return $this->nodes[$node]["name"];
2575      }
2576      
2577      /**
2578      * Handles the XPath function string.
2579      *
2580      * This method handles the XPath function string.
2581      *
2582      * @access    private
2583      * @author    Michael P. Mehl <mpm@phpxml.org>
2584      * @param     string $node Full path of the node on which the function
2585      *            should be processed.
2586      * @param     string $arguments String containing the arguments that were
2587      *            passed to the function.
2588      * @return    mixed Depending on the type of function being processed this 
2589      *            method returns different types.
2590      * @see       evaluate()
2591      */
2592      function handle_function_string ( $node, $arguments )
2593      {
2594          // Check what type of parameter is given
2595          if ( ereg("^[0-9]+(\.[0-9]+)?$", $arguments) ||
2596              ereg("^\.[0-9]+$", $arguments) )
2597          {
2598              // Convert the digits to a number.
2599              $number = doubleval($arguments);
2600                  
2601              // Return the number.
2602              return strval($number);
2603          }
2604          elseif ( is_bool($arguments) )
2605          {
2606              // Check whether it's true.
2607              if ( $arguments == true )
2608              {
2609                  // Return true as a string.
2610                  return "true";
2611              }
2612              else
2613              {
2614                  // Return false as a string.
2615                  return "false";
2616              }
2617          }
2618          elseif ( !empty($arguments) )
2619          {
2620              // Use the argument as an XPath.
2621              $result = $this->evaluate($arguments, $node);
2622                  
2623              // Get the first argument.
2624              $result = explode("|", implode("|", $result));
2625                  
2626              // Return the first result as a string.
2627              return $result[0];
2628          }
2629          elseif ( empty($arguments) )
2630          {
2631              // Return the current node.
2632              return $node;
2633          }
2634          else
2635          {
2636              // Return an empty string.
2637              return "";
2638          }
2639      }
2640      
2641      /**
2642      * Handles the XPath function concat.
2643      *
2644      * This method handles the XPath function concat.
2645      *
2646      * @access    private
2647      * @author    Michael P. Mehl <mpm@phpxml.org>
2648      * @param     string $node Full path of the node on which the function
2649      *            should be processed.
2650      * @param     string $arguments String containing the arguments that were
2651      *            passed to the function.
2652      * @return    mixed Depending on the type of function being processed this 
2653      *            method returns different types.
2654      * @see       evaluate()
2655      */
2656      function handle_function_concat ( $node, $arguments )
2657      {
2658          // Split the arguments.
2659          $arguments = explode(",", $arguments);
2660              
2661          // Run through each argument and evaluate it.
2662          for ( $i = 0; $i < sizeof($arguments); $i++ )
2663          {
2664              // Trim each argument.
2665              $arguments[$i] = trim($arguments[$i]);
2666                  
2667              // Evaluate it.
2668              $arguments[$i] = $this->evaluate_predicate($node, $arguments[$i]);
2669          }
2670              
2671          // Put the string together.
2672          $arguments = implode("", $arguments);
2673              
2674          // Return the string.
2675          return $arguments;
2676      }
2677      
2678      /**
2679      * Handles the XPath function starts-with.
2680      *
2681      * This method handles the XPath function starts-with.
2682      *
2683      * @access    private
2684      * @author    Michael P. Mehl <mpm@phpxml.org>
2685      * @param     string $node Full path of the node on which the function
2686      *            should be processed.
2687      * @param     string $arguments String containing the arguments that were
2688      *            passed to the function.
2689      * @return    mixed Depending on the type of function being processed this 
2690      *            method returns different types.
2691      * @see       evaluate()
2692      */
2693      function handle_function_starts_with ( $node, $arguments )
2694      {
2695          // Get the arguments.
2696          $first  = trim($this->prestr($arguments, ","));
2697          $second = trim($this->afterstr($arguments, ","));
2698              
2699          // Evaluate each argument.
2700          $first  = $this->evaluate_predicate($node, $first);
2701          $second = $this->evaluate_predicate($node, $second);
2702              
2703          // Check whether the first string starts with the second one.
2704          if ( ereg("^".$second, $first) )
2705          {
2706              // Return true.
2707              return true;
2708          }
2709          else
2710          {
2711              // Return false.
2712              return false;
2713          }
2714      }
2715      
2716      /**
2717      * Handles the XPath function contains.
2718      *
2719      * This method handles the XPath function contains.
2720      *
2721      * @access    private
2722      * @author    Michael P. Mehl <mpm@phpxml.org>
2723      * @param     string $node Full path of the node on which the function
2724      *            should be processed.
2725      * @param     string $arguments String containing the arguments that were
2726      *            passed to the function.
2727      * @return    mixed Depending on the type of function being processed this 
2728      *            method returns different types.
2729      * @see       evaluate()
2730      */
2731      function handle_function_contains ( $node, $arguments )
2732      {
2733          // Get the arguments.
2734          $first  = trim($this->prestr($arguments, ","));
2735          $second = trim($this->afterstr($arguments, ","));
2736              
2737          // Evaluate each argument.
2738          $first  = $this->evaluate_predicate($node, $first);
2739          $second = $this->evaluate_predicate($node, $second);
2740              
2741          // Check whether the first string starts with the second one.
2742          if ( ereg($second, $first) )
2743          {
2744              // Return true.
2745              return true;
2746          }
2747          else
2748          {
2749              // Return false.
2750              return false;
2751          }
2752      }
2753      
2754      /**
2755      * Handles the XPath function substring-before.
2756      *
2757      * This method handles the XPath function substring-before.
2758      *
2759      * @access    private
2760      * @author    Michael P. Mehl <mpm@phpxml.org>
2761      * @param     string $node Full path of the node on which the function
2762      *            should be processed.
2763      * @param     string $arguments String containing the arguments that were
2764      *            passed to the function.
2765      * @return    mixed Depending on the type of function being processed this 
2766      *            method returns different types.
2767      * @see       evaluate()
2768      */
2769      function handle_function_substring_before ( $node, $arguments )
2770      {
2771          // Get the arguments.
2772          $first  = trim($this->prestr($arguments, ","));
2773          $second = trim($this->afterstr($arguments, ","));
2774            
2775          // Evaluate each argument.
2776          $first  = $this->evaluate_predicate($node, $first);
2777          $second = $this->evaluate_predicate($node, $second);
2778              
2779          // Return the substring.
2780          return $this->prestr(strval($first), strval($second));
2781      }
2782      
2783      /**
2784      * Handles the XPath function substring-after.
2785      *
2786      * This method handles the XPath function substring-after.
2787      *
2788      * @access    private
2789      * @author    Michael P. Mehl <mpm@phpxml.org>
2790      * @param     string $node Full path of the node on which the function
2791      *            should be processed.
2792      * @param     string $arguments String containing the arguments that were
2793      *            passed to the function.
2794      * @return    mixed Depending on the type of function being processed this 
2795      *            method returns different types.
2796      * @see       evaluate()
2797      */
2798      function handle_function_substring_after ( $node, $arguments )
2799      {
2800          // Get the arguments.
2801          $first  = trim($this->prestr($arguments, ","));
2802          $second = trim($this->afterstr($arguments, ","));
2803              
2804          // Evaluate each argument.
2805          $first  = $this->evaluate_predicate($node, $first);
2806          $second = $this->evaluate_predicate($node, $second);
2807              
2808          // Return the substring.
2809          return $this->afterstr(strval($first), strval($second));
2810      }
2811      
2812      /**
2813      * Handles the XPath function substring.
2814      *
2815      * This method handles the XPath function substring.
2816      *
2817      * @access    private
2818      * @author    Michael P. Mehl <mpm@phpxml.org>
2819      * @param     string $node Full path of the node on which the function
2820      *            should be processed.
2821      * @param     string $arguments String containing the arguments that were
2822      *            passed to the function.
2823      * @return    mixed Depending on the type of function being processed this 
2824      *            method returns different types.
2825      * @see       evaluate()
2826      */
2827      function handle_function_substring ( $node, $arguments )
2828      {
2829          // Split the arguments.
2830          $arguments = explode(",", $arguments);
2831              
2832          // Run through all arguments.
2833          for ( $i = 0; $i < sizeof($arguments); $i++ )
2834          {
2835              // Trim the string.
2836              $arguments[$i] = trim($arguments[$i]);
2837                  
2838              // Evaluate each argument.
2839              $arguments[$i] = $this->evaluate_predicate($node, $arguments[$i]);
2840          }
2841              
2842          // Check whether a third argument was given.
2843          if ( !empty($arguments[2]) )
2844          {
2845              // Return the substring.
2846              return substr(strval($arguments[0]), $arguments[1] - 1,
2847                  $arguments[2]);
2848          }
2849          else
2850          {
2851              // Return the substring.
2852              return substr(strval($arguments[0]), $arguments[1] - 1);
2853          }
2854      }
2855      
2856      /**
2857      * Handles the XPath function string-length.
2858      *
2859      * This method handles the XPath function string-length.
2860      *
2861      * @access    private
2862      * @author    Michael P. Mehl <mpm@phpxml.org>
2863      * @param     string $node Full path of the node on which the function
2864      *            should be processed.
2865      * @param     string $arguments String containing the arguments that were
2866      *            passed to the function.
2867      * @return    mixed Depending on the type of function being processed this 
2868      *            method returns different types.
2869      * @see       evaluate()
2870      */
2871      function handle_function_string_length ( $node, $arguments )
2872      {
2873          // Trim the argument.
2874          $arguments = trim($arguments);
2875              
2876          // Evaluate the argument.
2877          $arguments = $this->evaluate_predicate($node, $arguments);
2878              
2879          // Return the length of the string.
2880          return strlen(strval($arguments));
2881      }
2882      
2883      /**
2884      * Handles the XPath function translate.
2885      *
2886      * This method handles the XPath function translate.
2887      *
2888      * @access    private
2889      * @author    Michael P. Mehl <mpm@phpxml.org>
2890      * @param     string $node Full path of the node on which the function
2891      *            should be processed.
2892      * @param     string $arguments String containing the arguments that were
2893      *            passed to the function.
2894      * @return    mixed Depending on the type of function being processed this 
2895      *            method returns different types.
2896      * @see       evaluate()
2897      */
2898      function handle_function_translate ( $node, $arguments )         
2899      {
2900          // Split the arguments.
2901          $arguments = explode(",", $arguments);
2902          
2903          // Run through all arguments.
2904          for ( $i = 0; $i < sizeof($arguments); $i++ )
2905          {
2906              // Trim the argument.
2907              $arguments[$i] = trim($arguments[$i]);
2908              
2909              // Evaluate the argument.
2910              $arguments[$i] = $this->evaluate_predicate($node, $arguments[$i]);
2911          }
2912              
2913          // Return the translated string.
2914          return strtr($arguments[0], $arguments[1], $arguments[2]);
2915      }
2916      
2917      /**
2918      * Handles the XPath function boolean.
2919      *
2920      * This method handles the XPath function boolean.
2921      *
2922      * @access    private
2923      * @author    Michael P. Mehl <mpm@phpxml.org>
2924      * @param     string $node Full path of the node on which the function
2925      *            should be processed.
2926      * @param     string $arguments String containing the arguments that were
2927      *            passed to the function.
2928      * @return    mixed Depending on the type of function being processed this 
2929      *            method returns different types.
2930      * @see       evaluate()
2931      */
2932      function handle_function_boolean ( $node, $arguments )
2933      {
2934          // Trim the arguments.
2935          $arguments = trim($arguments);
2936          
2937          // Check what type of parameter is given
2938          if ( ereg("^[0-9]+(\.[0-9]+)?$", $arguments) ||
2939              ereg("^\.[0-9]+$", $arguments) )
2940          {
2941              // Convert the digits to a number.
2942              $number = doubleval($arguments);
2943              
2944              // Check whether the number zero.
2945              if ( $number == 0 )
2946              {
2947                  // Return false.
2948                  return false;
2949              }
2950              else
2951              {
2952                  // Return true.
2953                  return true;
2954              }
2955          }
2956          elseif ( empty($arguments) )
2957          {
2958              // Sorry, there were no arguments.
2959              return false;
2960          }
2961          else
2962          {
2963              // Try to evaluate the argument as an XPath.
2964              $result = $this->evaluate($arguments, $node);
2965              
2966              // Check whether we found something.
2967              if ( count($result) > 0 )
2968              {
2969                  // Return true.
2970                  return true;
2971              }
2972              else
2973              {
2974                  // Return false.
2975                  return false;
2976              }
2977          }
2978      }
2979      
2980      /**
2981      * Handles the XPath function not.
2982      *
2983      * This method handles the XPath function not.
2984      *
2985      * @access    private
2986      * @author    Michael P. Mehl <mpm@phpxml.org>
2987      * @param     string $node Full path of the node on which the function
2988      *            should be processed.
2989      * @param     string $arguments String containing the arguments that were
2990      *            passed to the function.
2991      * @return    mixed Depending on the type of function being processed this 
2992      *            method returns different types.
2993      * @see       evaluate()
2994      */
2995      function handle_function_not ( $node, $arguments )
2996      {
2997          // Trim the arguments.
2998          $arguments = trim($arguments);
2999          
3000          // Return the negative value of the content of the brackets.
3001          return !$this->evaluate_predicate($node, $arguments);
3002      }
3003      
3004      /**
3005      * Handles the XPath function true.
3006      *
3007      * This method handles the XPath function true.
3008      *
3009      * @access    private
3010      * @author    Michael P. Mehl <mpm@phpxml.org>
3011      * @param     string $node Full path of the node on which the function
3012      *            should be processed.
3013      * @param     string $arguments String containing the arguments that were
3014      *            passed to the function.
3015      * @return    mixed Depending on the type of function being processed this 
3016      *            method returns different types.
3017      * @see       evaluate()
3018      */
3019      function handle_function_true ( $node, $arguments )
3020      {
3021          // Return true.
3022          return true;
3023      }
3024      
3025      /**
3026      * Handles the XPath function false.
3027      *
3028      * This method handles the XPath function false.
3029      *
3030      * @access    private
3031      * @author    Michael P. Mehl <mpm@phpxml.org>
3032      * @param     string $node Full path of the node on which the function
3033      *            should be processed.
3034      * @param     string $arguments String containing the arguments that were
3035      *            passed to the function.
3036      * @return    mixed Depending on the type of function being processed this 
3037      *            method returns different types.
3038      * @see       evaluate()
3039      */
3040      function handle_function_false ( $node, $arguments )
3041      {
3042          // Return false.
3043          return false;
3044      }
3045      
3046      /**
3047      * Handles the XPath function lang.
3048      *
3049      * This method handles the XPath function lang.
3050      *
3051      * @access    private
3052      * @author    Michael P. Mehl <mpm@phpxml.org>
3053      * @param     string $node Full path of the node on which the function
3054      *            should be processed.
3055      * @param     string $arguments String containing the arguments that were
3056      *            passed to the function.
3057      * @return    mixed Depending on the type of function being processed this 
3058      *            method returns different types.
3059      * @see       evaluate()
3060      */
3061      function handle_function_lang ( $node, $arguments )
3062      {
3063          // Trim the arguments.
3064          $arguments = trim($arguments);
3065          
3066          // Check whether the node has an language attribute.
3067          if ( empty($this->nodes[$node]["attributes"]["xml:lang"]) )
3068          {
3069              // Run through the ancestors.
3070              while ( !empty($node) )
3071              {
3072                  // Select the parent node.
3073                  $node = $this->nodes[$node]["parent"];
3074                  
3075                  // Check whether there's a language definition.
3076                  if ( !empty($this->nodes[$node]["attributes"]["xml:lang"]) )
3077                  {
3078                      // Check whether it's the language, the user asks for.
3079                      if ( eregi("^".$arguments, $this->nodes[$node]
3080                          ["attributes"]["xml:lang"]) )
3081                      {
3082                          // Return true.
3083                          return true;
3084                      }
3085                      else
3086                      {
3087                          // Return false.
3088                          return false;
3089                      }
3090                  }
3091              }
3092              
3093              // Return false.
3094              return false;
3095          }
3096          else
3097          {
3098              // Check whether it's the language, the user asks for.
3099              if ( eregi("^".$arguments, $this->nodes[$node]["attributes"]
3100                  ["xml:lang"]) )
3101              {
3102                  // Return true.
3103                  return true;
3104              }
3105              else
3106              {
3107                  // Return false.
3108                  return false;
3109              }
3110          }
3111      }
3112      
3113      /**
3114      * Handles the XPath function number.
3115      *
3116      * This method handles the XPath function number.
3117      *
3118      * @access    private
3119      * @author    Michael P. Mehl <mpm@phpxml.org>
3120      * @param     string $node Full path of the node on which the function
3121      *            should be processed.
3122      * @param     string $arguments String containing the arguments that were
3123      *            passed to the function.
3124      * @return    mixed Depending on the type of function being processed this 
3125      *            method returns different types.
3126      * @see       evaluate()
3127      */
3128      function handle_function_number ( $node, $arguments )
3129      {
3130          // Check the type of argument.
3131          if ( ereg("^[0-9]+(\.[0-9]+)?$", $arguments) ||
3132              ereg("^\.[0-9]+$", $arguments) )
3133          {
3134              // Return the argument as a number.
3135              return doubleval($arguments);
3136          }
3137          elseif ( is_bool($arguments) )
3138          {
3139              // Check whether it's true.
3140              if ( $arguments == true )
3141              {
3142                  // Return 1.
3143                  return 1;
3144              }
3145              else
3146              {
3147                  // Return 0.
3148                  return 0;
3149              }
3150          }
3151      }
3152      
3153      /**
3154      * Handles the XPath function sum.
3155      *
3156      * This method handles the XPath function sum.
3157      *
3158      * @access    private
3159      * @author    Michael P. Mehl <mpm@phpxml.org>
3160      * @param     string $node Full path of the node on which the function
3161      *            should be processed.
3162      * @param     string $arguments String containing the arguments that were
3163      *            passed to the function.
3164      * @return    mixed Depending on the type of function being processed this 
3165      *            method returns different types.
3166      * @see       evaluate()
3167      */
3168      function handle_function_sum ( $node, $arguments )
3169      {
3170          // Trim the arguments.
3171          $arguments = trim($arguments);
3172          
3173          // Evaluate the arguments as an XPath expression.
3174          $results = $this->evaluate($arguments, $node);
3175          
3176          // Create a variable to save the sum.
3177          $sum = 0;
3178          
3179          // Run through all results.
3180          foreach ( $results as $result )
3181          {
3182              // Get the value of the node.
3183              $result = $this->get_content($result);
3184              
3185              // Add it to the sum.
3186              $sum += doubleval($result);
3187          }
3188          
3189          // Return the sum.
3190          return $sum;
3191      }
3192      
3193      /**
3194      * Handles the XPath function floor.
3195      *
3196      * This method handles the XPath function floor.
3197      *
3198      * @access    private
3199      * @author    Michael P. Mehl <mpm@phpxml.org>
3200      * @param     string $node Full path of the node on which the function
3201      *            should be processed.
3202      * @param     string $arguments String containing the arguments that were
3203      *            passed to the function.
3204      * @return    mixed Depending on the type of function being processed this 
3205      *            method returns different types.
3206      * @see       evaluate()
3207      */
3208      function handle_function_floor ( $node, $arguments )
3209      {
3210          // Trim the arguments.
3211          $arguments = trim($arguments);
3212          
3213          // Convert the arguments to a number.
3214          $arguments = doubleval($arguments);
3215          
3216          // Return the result
3217          return floor($arguments);
3218      }
3219      
3220      /**
3221      * Handles the XPath function ceiling.
3222      *
3223      * This method handles the XPath function ceiling.
3224      *
3225      * @access    private
3226      * @author    Michael P. Mehl <mpm@phpxml.org>
3227      * @param     string $node Full path of the node on which the function
3228      *            should be processed.
3229      * @param     string $arguments String containing the arguments that were
3230      *            passed to the function.
3231      * @return    mixed Depending on the type of function being processed this 
3232      *            method returns different types.
3233      * @see       evaluate()
3234      */
3235      function handle_function_ceiling ( $node, $arguments )
3236      {
3237          // Trim the arguments.
3238          $arguments = trim($arguments);
3239          
3240          // Convert the arguments to a number.
3241          $arguments = doubleval($arguments);
3242          
3243          // Return the result
3244          return ceil($arguments);
3245      }
3246      
3247      /**
3248      * Handles the XPath function round.
3249      *
3250      * This method handles the XPath function round.
3251      *
3252      * @access    private
3253      * @author    Michael P. Mehl <mpm@phpxml.org>
3254      * @param     string $node Full path of the node on which the function
3255      *            should be processed.
3256      * @param     string $arguments String containing the arguments that were
3257      *            passed to the function.
3258      * @return    mixed Depending on the type of function being processed this 
3259      *            method returns different types.
3260      * @see       evaluate()
3261      */
3262      function handle_function_round ( $node, $arguments )
3263      {
3264          // Trim the arguments.
3265          $arguments = trim($arguments);
3266          
3267          // Convert the arguments to a number.
3268          $arguments = doubleval($arguments);
3269          
3270          // Return the result
3271          return round($arguments);
3272      }
3273      
3274      /**
3275      * Handles the XPath function text.
3276      *
3277      * This method handles the XPath function text.
3278      *
3279      * @access    private
3280      * @author    Michael P. Mehl <mpm@phpxml.org>
3281      * @param     string $node Full path of the node on which the function
3282      *            should be processed.
3283      * @param     string $arguments String containing the arguments that were
3284      *            passed to the function.
3285      * @return    mixed Depending on the type of function being processed this 
3286      *            method returns different types.
3287      * @see       evaluate()
3288      */
3289      function handle_function_text ( $node, $arguments )
3290      {
3291          // Return the character data of the node.
3292          return $this->nodes[$node]["text"];
3293      }
3294      
3295      /**
3296      * Retrieves a substring before a delimiter.
3297      *
3298      * This method retrieves everything from a string before a given delimiter,
3299      * not including the delimiter.
3300      *
3301      * @access    private
3302      * @author    Michael P. Mehl <mpm@phpxml.org>
3303      * @param     string $string String, from which the substring should be
3304      *            extracted.
3305      * @param     string $delimiter String containing the delimiter to use.
3306      * @return    string Substring from the original string before the
3307      *            delimiter.
3308      * @see       afterstr()
3309      */
3310      function prestr ( $string, $delimiter )
3311      {
3312          // Return the substring.
3313          return substr($string, 0, strlen($string) - strlen(strstr($string,
3314              "$delimiter")));
3315      }
3316      
3317      /**
3318      * Retrieves a substring after a delimiter.
3319      *
3320      * This method retrieves everything from a string after a given delimiter,
3321      * not including the delimiter.
3322      *
3323      * @access    private
3324      * @author    Michael P. Mehl <mpm@phpxml.org>
3325      * @param     string $string String, from which the substring should be
3326      *            extracted.
3327      * @param     string $delimiter String containing the delimiter to use.
3328      * @return    string Substring from the original string after the
3329      *            delimiter.
3330      * @see       prestr()
3331      */
3332      function afterstr ( $string, $delimiter )
3333      {
3334          // Return the substring.
3335          return substr($string,
3336              strpos($string, $delimiter) + strlen($delimiter));
3337      }
3338      
3339      /**
3340      * Displays an error message.
3341      *
3342      * This method displays an error messages and stops the execution of the
3343      * script. This method is called exactly in the same way as the printf
3344      * function. The first argument contains the message and additional
3345      * arguments of various types may be passed to this method to be inserted
3346      * into the message.
3347      *
3348      * @access    private
3349      * @author    Michael P. Mehl <mpm@phpxml.org>
3350      * @param     string $message Error message to be displayed.
3351      */
3352      function display_error ( $message )
3353      {
3354          // Check whether more than one argument was given.
3355          if ( func_num_args() > 1 )
3356          {
3357              // Read all arguments.
3358              $arguments = func_get_args();
3359              
3360              // Create a new string for the inserting command.
3361              $command = "\$message = sprintf(\$message, ";
3362              
3363              // Run through the array of arguments.
3364              for ( $i = 1; $i < sizeof($arguments); $i++ )
3365              {
3366                  // Add the number of the argument to the command.
3367                  $command .= "\$arguments[".$i."], ";
3368              }
3369              
3370              // Replace the last separator.
3371              $command = eregi_replace(", $", ");", $command);
3372              
3373              // Execute the command.
3374              eval($command);
3375          }
3376          
3377          // Display the error message.
3378          echo "<b>phpXML error:</b> ".$message;
3379          
3380          // End the execution of this script.
3381          exit;
3382      }
3383  }
3384  
3385  ?>


Généré le : Sun Feb 25 17:20:01 2007 par Balluche grâce à PHPXref 0.7