Browse Source

Create rdf_parser.php

nsITobin 4 months ago
parent
commit
5ca0cb57e7
1 changed files with 1297 additions and 0 deletions
  1. 1297 0
      reference/rdf_parser.php

+ 1297 - 0
reference/rdf_parser.php

@@ -0,0 +1,1297 @@
+<?php
+// ##################################################################################
+// Title                     : Class Rdf_parser
+// Version                   : 1.5.0
+// Author                    : Jason Diammond -repat RDF parser-
+//                           : Luis Argerich -PHP version of repat- (lrargerich@yahoo.com)
+//                           : Matt A. Tobin -Continued PHP Compat- (email@mattatobin.com)
+// Last modification date    : See history below..
+// Description               : A port to PHP of the Repat an RDF parser.
+//                             This parser based on expat parses RDF files producing events
+//                             proper of RDF documents.
+// ##################################################################################
+// History:
+// 06-13-2002                : First version of this class.
+// 07-17-2002                : Minor bugfix (Leandro Mariano Lopez)
+// 08-16-2006                : Allowed for user callback function to be in a class
+//                             (Justin Scott)
+// 10-05-2017                : Fixed issues with PHP 7 namely the ereg() polyfill
+// 12-21-2018                : Fix rdf parser lib for outdated usage of call_user_func
+// 02-26-2020                : PHP 7.4 Compat
+// ??-??-2021                : PHP 8.x Compat
+// 02-17-2022                : Use constants for common chars
+// ##################################################################################
+// To-Dos:
+//   Keep it working..
+// ##################################################################################
+// How to use it:
+// Read the documentation in rdf_parser.html
+// ##################################################################################
+
+class Rdf_parser {
+  const EMPTY_STRING                    = '';
+  const DOT                             = '.';
+  const DASH                            = '-';
+  const UNDERSCORE                      = '_';
+  const COLON                           = ':';
+
+  const XML_NAMESPACE_URI               = 'http://www.w3.org/XML/1998/namespace';
+  const XML_LANG                        = 'lang';
+  const RDF_NAMESPACE_URI               = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+  const RDF_RDF                         = 'RDF';
+  const RDF_DESCRIPTION                 = 'Description';
+  const RDF_ID                          = 'ID';
+  const RDF_ABOUT                       = 'about';
+  const RDF_ABOUT_EACH                  = 'aboutEach';
+  const RDF_ABOUT_EACH_PREFIX           = 'aboutEachPrefix';
+  const RDF_BAG_ID                      = 'bagID';
+  const RDF_RESOURCE                    = 'resource';
+  const RDF_VALUE                       = 'value';
+  const RDF_PARSE_TYPE                  = 'parseType';
+  const RDF_PARSE_TYPE_LITERAL          = 'Literal';
+  const RDF_PARSE_TYPE_RESOURCE         = 'Resource';
+  const RDF_TYPE                        = 'type';
+  const RDF_BAG                         = 'Bag';
+  const RDF_SEQ                         = 'Seq';
+  const RDF_ALT                         = 'Alt';
+  const RDF_LI                          = 'li';
+  const RDF_STATEMENT                   = 'Statement';
+  const RDF_SUBJECT                     = 'subject';
+  const RDF_PREDICATE                   = 'predicate';
+  const RDF_OBJECT                      = 'object';
+
+  const NAMESPACE_SEPARATOR_CHAR        = '^';
+  const NAMESPACE_SEPARATOR_STRING      = '^';
+
+  const IN_TOP_LEVEL                    = 0;
+  const IN_RDF                          = 1;
+  const IN_DESCRIPTION                  = 2;
+  const IN_PROPERTY_UNKNOWN_OBJECT      = 3;
+  const IN_PROPERTY_RESOURCE            = 4;
+  const IN_PROPERTY_EMPTY_RESOURCE      = 5;
+  const IN_PROPERTY_LITERAL             = 6;
+  const IN_PROPERTY_PARSE_TYPE_LITERAL  = 7;
+  const IN_PROPERTY_PARSE_TYPE_RESOURCE = 8;
+  const IN_XML                          = 9;
+  const IN_UNKNOWN                      = 10;
+
+  const RDF_SUBJECT_TYPE_URI            = 0;
+  const RDF_SUBJECT_TYPE_DISTRIBUTED    = 1;
+  const RDF_SUBJECT_TYPE_PREFIX         = 2;
+  const RDF_SUBJECT_TYPE_ANONYMOUS      = 3;
+
+  const RDF_OBJECT_TYPE_RESOURCE        = 0;
+  const RDF_OBJECT_TYPE_LITERAL         = 1;
+  const RDF_OBJECT_TYPE_XML             = 2;
+
+  public $rdf_parser;
+
+  // --------------------------------------------------------------------------
+
+  public function rdf_parser_create($encoding) {
+    $parser = xml_parser_create_ns($encoding, self::NAMESPACE_SEPARATOR_CHAR);
+    xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+    $this->rdf_parser["xml_parser"] = $parser;
+
+    xml_set_object($this->rdf_parser["xml_parser"], $this);
+    xml_set_element_handler($this->rdf_parser["xml_parser"], "_start_element_handler", "_end_element_handler");
+    xml_set_character_data_handler($this->rdf_parser["xml_parser"], "_character_data_handler");
+
+    return $this->rdf_parser;
+  }
+
+  public function rdf_parser_free() {
+    $z = 3;
+    //    xml_parser_free( $this->rdf_parser["xml_parser"] );
+    $this->rdf_parser["base_uri"] = self::EMPTY_STRING;
+
+    $this->_delete_elements($this->rdf_parser);
+
+    unset($this->rdf_parser);
+  }
+
+  public function rdf_set_user_data(&$user_data) {
+    $this->rdf_parser["user_data"] = & $user_data;
+  }
+
+  public function rdf_get_user_data() {
+    return ($this->rdf_parser["$user_data"]);
+  }
+
+  public function rdf_set_statement_handler($handler) {
+    $this->rdf_parser["statement_handler"] = $handler;
+  }
+
+  public function rdf_set_parse_type_literal_handler($start, $end) {
+    $this->rdf_parser["start_parse_type_literal_handler"] = $start;
+    $this->rdf_parser["end_parse_type_literal_handler"] = $end;
+  }
+
+  public function rdf_set_element_handler($start, $end) {
+    $this->rdf_parser["_start_element_handler"] = $start;
+    $this->rdf_parser["_end_element_handler"] = $end;
+  }
+
+  public function rdf_set_character_data_handler($handler) {
+    $this->rdf_parser["_character_data_handler"] = $handler;
+  }
+
+  public function rdf_set_warning_handler($handler) {
+    $this->rdf_parser["warning_handler"] = $handler;
+  }
+
+  public function rdf_parse($s, $len, $is_final) {
+    return XML_Parse($this->rdf_parser["xml_parser"], $s, $is_final);
+  }
+
+  public function rdf_get_xml_parser() {
+    return ($this->rdf_parser["xml_parser"]);
+  }
+
+  public function rdf_set_base($base) {
+    /* check for out of memory */
+    $this->rdf_parser["base_uri"] = $base;
+
+    return 0;
+  }
+
+  public function rdf_get_base() {
+    return $this->rdf_parser["base_uri"];
+  }
+
+  public function rdf_resolve_uri($uri_reference, &$buffer) {
+    _resolve_uri_reference($this->rdf_parser["base_uri"], $uri_reference, $buffer, strlen($buffer));
+  }
+
+  // --------------------------------------------------------------------------
+
+  private function _new_element() {
+    $e["parent"] = Array(); // Parent is a blank Array
+    //$this->clear_element($e["parent"]);
+    $e["state"] = 0;
+    $e["has_property_atributes"] = 0;
+    $e["has_member_attributes"] = 0;
+    $e["subject_type"] = 0;
+    $e["subject"] = self::EMPTY_STRING;
+    $e["predicate"] = self::EMPTY_STRING;
+    $e["ordinal"] = 0;
+    $e["members"] = 0;
+    $e["data"] = self::EMPTY_STRING;
+    $e["xml_lang"] = self::EMPTY_STRING;
+    $e["bag_id"] = self::EMPTY_STRING;
+    $e["statements"] = 0;
+    $e["statement_id"] = self::EMPTY_STRING;
+
+    return $e;
+  }
+
+  private function _copy_element($source, &$destination) {
+    if ($source) {
+      $destination["parent"] = $source;
+      $destination["state"] = $source["state"];
+      $destination["xml_lang"] = $source["xml_lang"];
+    }
+  }
+
+  private function _clear_element(&$e) {
+    $e["subject"] = self::EMPTY_STRING;
+    $e["predicate"] = self::EMPTY_STRING;
+    $e["data"] = self::EMPTY_STRING;
+    $e["bag_id"] = self::EMPTY_STRING;
+    $e["statement_id"] = self::EMPTY_STRING;
+
+    if (isset($e["parent"])) {
+      if ($e["parent"]) {
+        if ($e["parent"]["xml_lang"] != $e["xml_lang"]) {
+          $e["xml_lang"] = self::EMPTY_STRING;
+        }
+      }
+      else {
+        $e["xml_lang"] = self::EMPTY_STRING;
+      }
+    }
+    else {
+      $e["xml_lang"] = self::EMPTY_STRING;
+    }
+
+    //memset( e, 0, strlen( _rdf_element ) );
+    $e["parent"] = Array();
+    $e["state"] = 0;
+    $e["has_property_attributes"] = 0;
+    $e["has_member_attributes"] = 0;
+    $e["subject_type"] = 0;
+    $e["subject"] = self::EMPTY_STRING;
+    $e["predicate"] = self::EMPTY_STRING;
+    $e["ordinal"] = 0;
+    $e["members"] = 0;
+    $e["data"] = self::EMPTY_STRING;
+    $e["xml_lang"] = self::EMPTY_STRING;
+    $e["bag_id"] = self::EMPTY_STRING;
+    $e["statements"] = 0;
+    $e["statement_id"] = self::EMPTY_STRING;
+
+  }
+
+  private function _push_element() {
+    if (!isset($this->rdf_parser["free"])) {
+      $this->rdf_parser["free"] = Array();
+    }
+
+    if (count($this->rdf_parser["free"]) > 0) {
+      $e = $this->rdf_parser["free"];
+      if (isset($e["parent"])) {
+        $this->rdf_parser["free"] = $e["parent"];
+      }
+      else {
+        $this->rdf_parser["free"] = $this->_new_element();
+      }
+    }
+    else {
+      $e = $this->_new_element();
+    }
+
+    if (!isset($this->rdf_parser["top"])) {
+      $this->rdf_parser["top"] = Array();
+    }
+
+    $this->_copy_element($this->rdf_parser["top"], $e);
+    $this->rdf_parser["top"] = $e;
+  }
+
+  private function _pop_element() {
+    $e = $this->rdf_parser["top"];
+    $this->rdf_parser["top"] = $e["parent"];
+    $this->_clear_element($e);
+    $this->rdf_parser["free"] = $e;
+  }
+
+  private function _delete_elements() {
+  }
+
+  private function _is_rdf_property_attribute_resource($local_name) {
+    return ($local_name == self::RDF_TYPE);
+  }
+
+  private function _is_rdf_property_attribute_literal($local_name) {
+    return ($local_name == self::RDF_VALUE);
+  }
+
+  private function _is_rdf_ordinal($local_name) {
+    $ordinal = - 1;
+
+    if ($local_name[0] == self::UNDERSCORE) {
+      $ordinal = substr($local_name, 1) + 1;
+    }
+
+    return ($ordinal > 0) ? $ordinal : 0;
+  }
+
+  private function _is_rdf_property_attribute($local_name) {
+    return $this->_is_rdf_property_attribute_resource($local_name) || $this->_is_rdf_property_attribute_literal($local_name);
+  }
+
+  private function _is_rdf_property_element($local_name) {
+    return
+      ($local_name == self::RDF_TYPE) || ($local_name == self::RDF_SUBJECT) || ($local_name == self::RDF_PREDICATE) ||
+      ($local_name == self::RDF_OBJECT) || ($local_name == self::RDF_VALUE) || ($local_name == self::RDF_LI) ||
+      ($local_name[0] == self::UNDERSCORE);
+  }
+
+  private function _istalnum($val) {
+    return preg_match("/[A-Za-z0-9]/", $val);
+  }
+
+  private function _istalpha($val) {
+    return preg_match("/[A-Za-z]/", $val);
+  }
+
+  private function _is_absolute_uri($uri) {
+    $result = false;
+    $uri_p = 0;
+    if ($uri && $this->_istalpha($uri[$uri_p])) {
+      ++$uri_p;
+
+    while (($uri_p < strlen($uri)) && ($this->_istalnum($uri[$uri_p]) || ($uri[$uri_p] == '+') || ($uri[$uri_p] == self::DASH) || ($uri[$uri_p] == self::DOT))) {
+        ++$uri_p;
+      }
+
+      $result = ($uri[$uri_p] == self::COLON);
+    }
+    return $result;
+  }
+
+  /*
+  This function returns an associative array returning any of the various components of the URL that are present. This includes the
+  $arr=parse_url($url)
+  scheme - e.g. http
+  host
+  port
+  user
+  pass
+  path
+  query - after the question mark ?
+  fragment - after the hashmark #
+  */
+  private function _parse_uri($uri, $buffer, $len, &$scheme, &$authority, &$path, &$query, &$fragment) {
+    $parsed = parse_url($uri);
+    if (isset($parsed["scheme"])) {
+      $scheme = $parsed["scheme"];
+    }
+    else {
+      $scheme = self::EMPTY_STRING;
+    }
+
+    if (isset($parsed["host"])) {
+      $host = $parsed["host"];
+    }
+    else {
+      $host = self::EMPTY_STRING;
+    }
+
+    if (isset($parsed["host"])) {
+      $authority = $parsed["host"];
+    }
+    else {
+      $authority = self::EMPTY_STRING;
+    }
+
+    if (isset($parsed["path"])) {
+      $path = $parsed["path"];
+    }
+    else {
+      $path = self::EMPTY_STRING;
+    }
+
+    if (isset($parsed["query"])) {
+      $query = $parsed["query"];
+    }
+    else {
+      $query = self::EMPTY_STRING;
+    }
+
+    if (isset($parsed["fragment"])) {
+      $fragment = $parsed["fragment"];
+    }
+    else {
+      $fragment = self::EMPTY_STRING;
+    }
+  }
+
+  private function _resolve_uri_reference($base_uri, $reference_uri, &$buffer, $length) {
+    $base_buffer = self::EMPTY_STRING;
+    $reference_buffer = self::EMPTY_STRING;
+    $path_buffer = self::EMPTY_STRING;
+
+    $buffer = self::EMPTY_STRING;
+
+    $this->_parse_uri($reference_uri, $reference_buffer, strlen($reference_buffer) , $reference_scheme, $reference_authority, $reference_path, $reference_query, $reference_fragment);
+
+    if ($reference_scheme == self::EMPTY_STRING && $reference_authority == self::EMPTY_STRING && $reference_path == self::EMPTY_STRING && $reference_query == self::EMPTY_STRING) {
+      $buffer = $base_uri;
+
+      if ($reference_fragment != self::EMPTY_STRING) {
+        $buffer .= "#";
+        $buffer .= $reference_fragment;
+      }
+    }
+    elseif ($reference_scheme != self::EMPTY_STRING) {
+      $buffer = $reference_uri;
+    }
+    else {
+      $this->_parse_uri($base_uri, $base_buffer, strlen($base_buffer) , $base_scheme, $base_authority, $base_path, $base_query, $base_fragment);
+
+      $result_scheme = $base_scheme;
+
+      if ($reference_authority != self::EMPTY_STRING) {
+        $result_authority = $reference_authority;
+      }
+      else {
+        $result_authority = $base_authority;
+
+        if ($reference_path != self::EMPTY_STRING && (($reference_path[0] == '/') || ($reference_path[0] == '\\'))) {
+          $result_path = $reference_path;
+        }
+        else {
+          $p = self::EMPTY_STRING;
+
+          $result_path = $path_buffer;
+
+          $path_buffer = self::EMPTY_STRING;
+
+          $p = strstr($base_path, '/');
+
+          if (!$p) {
+            $p = strstr($base_path, '\\');
+          }
+
+          if ($p) {
+
+            $path_buffer .= $base_path;
+
+            //while( s <= p )
+            //{
+            //  *d++ = *s++;
+            //}
+            //*d++ = 0;
+            
+          }
+
+          if ($reference_path != self::EMPTY_STRING) {
+            $path_buffer .= $reference_path;
+          }
+
+          //remove all occurrences of "./"
+          //print($path_buffer);
+          $path_buffer = preg_replace("/\/\.\//", "/", $path_buffer);
+          $path_buffer = preg_replace("/\/([^\/\.])*\/..$/", "/", $path_buffer);
+
+          while (preg_match("/\.\./", $path_buffer)) {
+            $path_buffer = preg_replace("/\/([^\/\.]*)\/..\//", "/", $path_buffer);
+          }
+
+          $path_buffer = preg_replace("/\.$/", "", $path_buffer);
+
+        }
+      }
+
+      // This replaces the C pointer assignament
+      $result_path = $path_buffer;
+      if ($result_scheme != self::EMPTY_STRING) {
+        $buffer = $result_scheme;
+        $buffer .= ":";
+      }
+
+      if ($result_authority != self::EMPTY_STRING) {
+        $buffer .= "//";
+        $buffer .= $result_authority;
+      }
+
+      if ($result_path != self::EMPTY_STRING) {
+
+        $buffer .= $result_path;
+      }
+
+      if ($reference_query != self::EMPTY_STRING) {
+        $buffer .= "?";
+        $buffer .= $reference_query;
+      }
+
+      if ($reference_fragment != self::EMPTY_STRING) {
+        $buffer .= "#";
+        $buffer .= $reference_fragment;
+      }
+    }
+  }
+
+  private function is_valid_id($id) {
+    $result = false;
+    $p = $id;
+    $p_p = 0;
+
+    if ($id != self::EMPTY_STRING) {
+      if ($this->_istalpha($p) || $p[0] == self::UNDERSCORE || $p[0] == self::COLON) {
+        $result = true;
+
+        while ($result != false && ($p[++$p_p] != 0)) {
+          if (!($this->_istalnum($p[$p_p]) || $p[$p_p] == self::DOT || $p[$p_p] == self::DASH || $p[$p_p] == self::UNDERSCORE || $p[$p_p] == self::COLON)) {
+            $result = false;
+          }
+        }
+      }
+    }
+
+    return $result;
+  }
+
+  private function _resolve_id($id, &$buffer, $length) {
+    $id_buffer = self::EMPTY_STRING;
+
+    if ($this->is_valid_id($id) == true) {
+      $id_buffer = "#$id";
+    }
+    else {
+      $this->report_warning("bad ID attribute: " . $id_buffer . "#_bad_ID_attribute_");
+    }
+
+    $this->_resolve_uri_reference($this->rdf_parser["base_uri"], $id_buffer, $buffer, $length);
+  }
+
+  private function _split_name($name, &$buffer, $len, &$namespace_uri, &$local_name) {
+
+    static $nul = 0;
+    $buffer = $name;
+
+    if (strstr($buffer, self::NAMESPACE_SEPARATOR_CHAR)) {
+      $cosas = explode(self::NAMESPACE_SEPARATOR_CHAR, $buffer);
+      $namespace_uri = $cosas[0];
+      $local_name = $cosas[1];
+    }
+    else {
+      if (($buffer[0] == 'x') && ($buffer[1] == 'm') && ($buffer[2] == 'l') && ($buffer[3] == self::COLON)) {
+        $namespace_uri = self::XML_NAMESPACE_URI;
+        $local_name = substr($buffer, 4);
+      }
+      else {
+        $namespace_uri = self::EMPTY_STRING;
+        $local_name = $buffer;
+      }
+    }
+
+  }
+
+  private function _generate_anonymous_uri(&$buf, $len) {
+    $id = self::EMPTY_STRING;
+    if (!isset($this->rdf_parser["anonymous_id"])) {
+      $this->rdf_parser["anonymous_id"] = 0;
+    }
+    $this->rdf_parser["anonymous_id"]++;
+
+    $id = "#genid" . $this->rdf_parser["anonymous_id"];
+    $this->_resolve_uri_reference($this->rdf_parser["base_uri"], $id, $buf, $len);
+
+  }
+
+  private function _report_statement($subject_type, $subject, $predicate, $ordinal, $object_type, $object, $xml_lang, $bag_id, $statements, $statement_id) {
+    $statement_id_type = self::RDF_SUBJECT_TYPE_URI;
+    $statement_id_buffer = self::EMPTY_STRING;
+    $predicate_buffer = self::EMPTY_STRING;
+
+    if ($this->rdf_parser["statement_handler"]) {
+      $this->rdf_parser["user_data"] = call_user_func_array($this->rdf_parser["statement_handler"], array(&$this->rdf_parser["user_data"], $subject_type, $subject, $predicate, $ordinal, $object_type, $object, $xml_lang));
+      // $this->rdf_parser["statement_handler"]($this->rdf_parser["user_data"],$subject_type,$subject,$predicate,$ordinal,$object_type,$object,$xml_lang )
+      if ($bag_id) {
+        if ($statements == self::EMPTY_STRING) {
+          $this->_report_statement(self::RDF_SUBJECT_TYPE_URI, $bag_id, self::RDF_NAMESPACE_URI . self::RDF_TYPE, 0, self::RDF_OBJECT_TYPE_RESOURCE, self::RDF_NAMESPACE_URI . self::RDF_BAG, self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING);
+        }
+
+        if (!$statement_id) {
+          $statement_id_type = self::RDF_SUBJECT_TYPE_ANONYMOUS;
+          $this->_generate_anonymous_uri($statement_id_buffer, strlen($statement_id_buffer));
+          $statement_id = $statement_id_buffer;
+        }
+        $statements++;
+        $predicate_buffer = "self::RDF_NAMESPACE_URI_" . $statements;
+
+        $this->_report_statement(self::RDF_SUBJECT_TYPE_URI, $bag_id, $predicate_buffer, $statements, self::RDF_OBJECT_TYPE_RESOURCE, $statement_id, self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING);
+      }
+
+      if ($statement_id) {
+        // rdf:type = rdf:Statement
+        $this->_report_statement(
+          $statement_id_type,
+          $statement_id,
+          self::RDF_NAMESPACE_URI . self::RDF_TYPE,
+          0,
+          self::RDF_OBJECT_TYPE_RESOURCE,
+          self::RDF_NAMESPACE_URI . self::RDF_STATEMENT,
+          self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING
+        );
+
+        // rdf:subject
+        $this->_report_statement(
+          $statement_id_type,
+          $statement_id,
+          self::RDF_NAMESPACE_URI . self::RDF_SUBJECT,
+          0,
+          self::RDF_OBJECT_TYPE_RESOURCE,
+          $subject,
+          self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING
+        );
+
+        // rdf:predicate
+        $this->_report_statement(
+          $statement_id_type,
+          $statement_id,
+          self::RDF_NAMESPACE_URI . self::RDF_PREDICATE,
+          0,
+          self::RDF_OBJECT_TYPE_RESOURCE,
+          $predicate,
+          self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING
+        );
+
+        // rdf:object
+        $this->_report_statement(
+          $statement_id_type,
+          $statement_id,
+          self::RDF_NAMESPACE_URI . self::RDF_OBJECT,
+          0,
+          $object_type,
+          $object,
+          self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING, self::EMPTY_STRING
+        );
+      }
+    }
+  }
+
+  private function _report_start_parse_type_literal() {
+    if ($this->rdf_parser["start_parse_type_literal_handler"]) {
+      $this->rdf_parser["start_parse_type_literal_handler"]($this->rdf_parser["user_data"]);
+    }
+  }
+
+  private function _report_end_parse_type_literal() {
+    if ($this->rdf_parser["end_parse_type_literal_handler"]) {
+      $this->rdf_parser["end_parse_type_literal_handler"]($this->rdf_parser["user_data"]);
+    }
+  }
+
+  private function _handle_property_attributes($subject_type, $subject, $attributes, $xml_lang, $bag_id, $statements) {
+    $i = 0;
+
+    $attribute = self::EMPTY_STRING;
+    $predicate = self::EMPTY_STRING;
+
+    $attribute_namespace_uri = self::EMPTY_STRING;
+    $attribute_local_name = self::EMPTY_STRING;
+    $attribute_value = self::EMPTY_STRING;
+
+    $ordinal = 0;
+
+    for ($i = 0;isset($attributes[$i]);$i += 2) {
+      $this->_split_name($attributes[$i], $attribute, strlen($attribute) , $attribute_namespace_uri, $attribute_local_name);
+
+      $attribute_value = $attributes[$i + 1];
+
+      $predicate = $attribute_namespace_uri;
+      $predicate .= $attribute_local_name;
+
+      if (self::RDF_NAMESPACE_URI == $attribute_namespace_uri) {
+        if ($this->_is_rdf_property_attribute_literal($attribute_local_name)) {
+          $this->_report_statement($subject_type, $subject, $predicate, 0, self::RDF_OBJECT_TYPE_LITERAL, $attribute_value, $xml_lang, $bag_id, $statements, self::EMPTY_STRING);
+        }
+        elseif ($this->_is_rdf_property_attribute_resource($attribute_local_name)) {
+          $this->_report_statement($subject_type, $subject, $predicate, 0, self::RDF_OBJECT_TYPE_RESOURCE, $attribute_value, self::EMPTY_STRING, $bag_id, $statements, self::EMPTY_STRING);
+        }
+        elseif (($ordinal = $this->_is_rdf_ordinal($attribute_local_name)) != 0) {
+          $this->_report_statement($subject_type, $subject, $predicate, $ordinal, self::RDF_OBJECT_TYPE_LITERAL, $attribute_value, $xml_lang, $bag_id, $statements, self::EMPTY_STRING);
+        }
+      }
+      elseif (self::XML_NAMESPACE_URI == $attribute_namespace_uri) {
+        //do nothing
+      }
+      elseif ($attribute_namespace_uri) {
+        // is it required that property attributes be in an explicit namespace?
+        $this->_report_statement($subject_type, $subject, $predicate, 0, self::RDF_OBJECT_TYPE_LITERAL, $attribute_value, $xml_lang, $bag_id, $statements, self::EMPTY_STRING);
+      }
+    }
+  }
+
+  private function _report_start_element($name, $attributes) {
+    if (isset($this->rdf_parser["start_element_handler"])) {
+      $this->rdf_parser["start_element_handler"]($this->rdf_parser["user_data"], $name, $attributes);
+    }
+  }
+
+  private function _report_end_element($name) {
+    if (isset($this->rdf_parser["end_element_handler"])) {
+      $this->rdf_parser["end_element_handler"]($this->rdf_parser["user_data"], $name);
+    }
+  }
+
+  private function _report_character_data($s, $len) {
+    if (isset($this->rdf_parser["character_data_handler"])) {
+      $this->rdf_parser["character_data_handler"]($this->rdf_parser["user_data"], $s, $len);
+    }
+  }
+
+  private function _report_warning($warning) {
+    // rdf_parser->top->state = self::IN_UNKNOWN;
+    if (isset($this->rdf_parser["warning_handler"])) {
+      $this->rdf_parser["warning_handler"]($warning);
+    }
+  }
+
+  private function _handle_resource_element($namespace_uri, $local_name, $attributes, $parent) {
+    $subjects_found = 0;
+    $aux = $attributes;
+    $aux2 = Array();
+
+    foreach ($attributes as $atkey => $atvalue) {
+      $aux2[] = $atkey;
+      $aux2[] = $atvalue;
+    }
+
+    $attributes = $aux2;
+    $id = self::EMPTY_STRING;
+    $about = self::EMPTY_STRING;
+    $about_each = self::EMPTY_STRING;
+    $about_each_prefix = self::EMPTY_STRING;
+
+    $bag_id = self::EMPTY_STRING;
+
+    $i = 0;
+
+    $attribute = self::EMPTY_STRING;
+
+    $attribute_namespace_uri = self::EMPTY_STRING;
+    $attribute_local_name = self::EMPTY_STRING;
+    $attribute_value = self::EMPTY_STRING;
+
+    $id_buffer = self::EMPTY_STRING;
+
+    $type = self::EMPTY_STRING;
+
+    $this->rdf_parser["top"]["has_property_attributes"] = false;
+    $this->rdf_parser["top"]["has_member_attributes"] = false;
+
+    // examine each attribute for the standard RDF "keywords"
+    for ($i = 0;isset($attributes[$i]);$i += 2) {
+      $this->_split_name($attributes[$i], $attribute, strlen($attribute) , $attribute_namespace_uri, $attribute_local_name);
+
+      $attribute_value = $attributes[$i + 1];
+
+      // if the attribute is not in any namespace
+      //   or the attribute is in the RDF namespace
+      if (($attribute_namespace_uri == self::EMPTY_STRING) || ($attribute_namespace_uri == self::RDF_NAMESPACE_URI)) {
+        if ($attribute_local_name == self::RDF_ID) {
+          $id = $attribute_value;
+          ++$subjects_found;
+        }
+        elseif ($attribute_local_name == self::RDF_ABOUT) {
+          $about = $attribute_value;
+          ++$subjects_found;
+        }
+        elseif ($attribute_local_name == self::RDF_ABOUT_EACH) {
+          $about_each = $attribute_value;
+          ++$subjects_found;
+        }
+        elseif ($attribute_local_name == self::RDF_ABOUT_EACH_PREFIX) {
+          $about_each_prefix = $attribute_value;
+          ++$subjects_found;
+        }
+        elseif ($attribute_local_name == self::RDF_BAG_ID) {
+          $bag_id = $attribute_value;
+        }
+        elseif ($this->_is_rdf_property_attribute($attribute_local_name)) {
+          $this->rdf_parser["top"]["has_property_attributes"] = true;
+        }
+        elseif ($this->_is_rdf_ordinal($attribute_local_name)) {
+          $this->rdf_parser["top"]["has_property_attributes"] = true;
+          $this->rdf_parser["top"]["has_member_attributes"] = true;
+        }
+        else {
+          $this->_report_warning("unknown or out of context rdf attribute:" . $attribute_local_name);
+        }
+      }
+      elseif ($attribute_namespace_uri == self::XML_NAMESPACE_URI) {
+        if ($attribute_local_name == self::XML_LANG) {
+          $this->rdf_parser["top"]["xml_lang"] = $attribute_value;
+        }
+      }
+      elseif ($attribute_namespace_uri) {
+        $this->rdf_parser["top"]["has_property_attributes"] = true;
+      }
+    }
+
+    // if no subjects were found, generate one.
+    if ($subjects_found == 0) {
+      $this->_generate_anonymous_uri($id_buffer, strlen($id_buffer));
+      $this->rdf_parser["top"]["subject"] = $id_buffer;
+      $this->rdf_parser["top"]["subject_type"] = self::RDF_SUBJECT_TYPE_ANONYMOUS;
+    }
+    elseif ($subjects_found > 1) {
+      $this->_report_warning("ID, about, aboutEach, and aboutEachPrefix are mutually exclusive");
+      return;
+    }
+    elseif ($id) {
+      $this->_resolve_id($id, $id_buffer, strlen($id_buffer));
+      $this->rdf_parser["top"]["subject_type"] = self::RDF_SUBJECT_TYPE_URI;
+      $this->rdf_parser["top"]["subject"] = $id_buffer;
+    }
+    elseif ($about) {
+      $this->_resolve_uri_reference($this->rdf_parser["base_uri"], $about, $id_buffer, strlen($id_buffer));
+      $this->rdf_parser["top"]["subject_type"] = self::RDF_SUBJECT_TYPE_URI;
+      $this->rdf_parser["top"]["subject"] = $id_buffer;
+    }
+    elseif ($about_each) {
+      $this->rdf_parser["top"]["subject_type"] = self::RDF_SUBJECT_TYPE_DISTRIBUTED;
+      $this->rdf_parser["top"]["subject"] = $about_each;
+    }
+    elseif ($about_each_prefix) {
+      $this->rdf_parser["top"]["subject_type"] = self::RDF_SUBJECT_TYPE_PREFIX;
+      $this->rdf_parser["top"]["subject"] = $about_each_prefix;
+    }
+
+    // if the subject is empty, assign it the document uri
+    if ($this->rdf_parser["top"]["subject"] == self::EMPTY_STRING) {
+      $len = 0;
+
+      $this->rdf_parser["top"]["subject"] = $this->rdf_parser["base_uri"];
+
+      // now remove the trailing '#'
+      $len = strlen($this->rdf_parser["top"]["subject"]);
+    }
+
+    if ($bag_id) {
+      $this->_resolve_id($bag_id, $id_buffer, strlen($id_buffer));
+      $this->rdf_parser["top"]["bag_id"] = $id_buffer;
+    }
+
+    // only report the type for non-rdf:Description elements.
+    if (($local_name != self::RDF_DESCRIPTION) || ($namespace_uri != self::RDF_NAMESPACE_URI)) {
+      $type = $namespace_uri;
+      $type .= $local_name;
+
+      $this->_report_statement(
+        $this->rdf_parser["top"]["subject_type"],
+        $this->rdf_parser["top"]["subject"],
+        self::RDF_NAMESPACE_URI . self::RDF_TYPE,
+        0,
+        self::RDF_OBJECT_TYPE_RESOURCE,
+        $type,
+        self::EMPTY_STRING,
+        $this->rdf_parser["top"]["bag_id"],
+        $this->rdf_parser["top"]["statements"],
+        self::EMPTY_STRING
+      );
+
+    }
+
+    // if this element is the child of some property,
+    //   report the appropriate statement.
+    if ($parent) {
+      $this->_report_statement(
+        $parent["parent"]["subject_type"],
+        $parent["parent"]["subject"],
+        $parent["predicate"],
+        $parent["ordinal"],
+        self::RDF_OBJECT_TYPE_RESOURCE,
+        $this->rdf_parser["top"]["subject"],
+        self::EMPTY_STRING,
+        $parent["parent"]["bag_id"],
+        $parent["parent"]["statements"],
+        $parent["statement_id"]
+      );
+    }
+
+    if ($this->rdf_parser["top"]["has_property_attributes"]) {
+      $this->_handle_property_attributes(
+        $this->rdf_parser["top"]["subject_type"],
+        $this->rdf_parser["top"]["subject"],
+        $attributes,
+        $this->rdf_parser["top"]["xml_lang"],
+        $this->rdf_parser["top"]["bag_id"],
+        $this->rdf_parser["top"]["statements"]
+      );
+    }
+  }
+
+  private function _handle_property_element(&$namespace_uri, &$local_name, &$attributes) {
+    $buffer = self::EMPTY_STRING;
+
+    $i = 0;
+
+    $aux = $attributes;
+    $aux2 = Array();
+
+    foreach ($attributes as $atkey => $atvalue) {
+      $aux2[] = $atkey;
+      $aux2[] = $atvalue;
+    }
+
+    $attributes = $aux2;
+
+    $attribute_namespace_uri = self::EMPTY_STRING;
+    $attribute_local_name = self::EMPTY_STRING;
+    $attribute_value = self::EMPTY_STRING;
+
+    $resource = self::EMPTY_STRING;
+    $statement_id = self::EMPTY_STRING;
+    $bag_id = self::EMPTY_STRING;
+    $parse_type = self::EMPTY_STRING;
+
+    $this->rdf_parser["top"]["ordinal"] = 0;
+
+    if ($namespace_uri == self::RDF_NAMESPACE_URI) {
+      if (($this->rdf_parser["top"]["ordinal"] = ($this->_is_rdf_ordinal($local_name)) != 0)) {
+        if ($this->rdf_parser["top"]["ordinal"] > $this->rdf_parser["top"]["parent"]["members"]) {
+          $this->rdf_parser["top"]["parent"]["members"] = $this->rdf_parser["top"]["ordinal"];
+        }
+      }
+      elseif (!$this->_is_rdf_property_element($local_name)) {
+        $this->_report_warning("unknown or out of context rdf property element: " . $local_name);
+        return;
+      }
+    }
+
+    $buffer = $namespace_uri;
+
+    if (($namespace_uri == self::RDF_NAMESPACE_URI) && ($local_name == self::RDF_LI)) {
+      //$ordinal=self::EMPTY_STRING;
+      $this->rdf_parser["top"]["parent"]["members"]++;
+      $this->rdf_parser["top"]["ordinal"] = $this->rdf_parser["top"]["parent"]["members"];
+
+      $this->rdf_parser["top"]["ordinal"] = $this->rdf_parser["top"]["ordinal"];
+      //$ordinal{ 0 } =  self::UNDERSCORE ;
+      $buffer .= self::UNDERSCORE . $this->rdf_parser["top"]["ordinal"];
+    }
+    else {
+      $buffer .= $local_name;
+    }
+
+    $this->rdf_parser["top"]["predicate"] = $buffer;
+
+    $this->rdf_parser["top"]["has_property_attributes"] = false;
+    $this->rdf_parser["top"]["has_member_attributes"] = false;
+
+    for ($i = 0;isset($attributes[$i]);$i += 2) {
+      $this->_split_name($attributes[$i], $buffer, strlen($buffer) , $attribute_namespace_uri, $attribute_local_name);
+
+      $attribute_value = $attributes[$i + 1];
+
+      // if the attribute is not in any namespace
+      //   or the attribute is in the RDF namespace
+      if (($attribute_namespace_uri == self::EMPTY_STRING) || ($attribute_namespace_uri == self::RDF_NAMESPACE_URI)) {
+        if (($attribute_local_name == self::RDF_ID)) {
+          $statement_id = $attribute_value;
+        }
+        elseif ($attribute_local_name == self::RDF_PARSE_TYPE) {
+          $parse_type = $attribute_value;
+        }
+        elseif ($attribute_local_name == self::RDF_RESOURCE) {
+          $resource = $attribute_value;
+        }
+        elseif ($attribute_local_name == self::RDF_BAG_ID) {
+          $bag_id = $attribute_value;
+        }
+        elseif ($this->_is_rdf_property_attribute($attribute_local_name)) {
+          $this->rdf_parser["top"]["has_property_attributes"] = true;
+        }
+        else {
+          $this->_report_warning("unknown rdf attribute: " . $attribute_local_name);
+          return;
+        }
+      }
+      elseif ($attribute_namespace_uri == self::XML_NAMESPACE_URI) {
+        if ($attribute_local_name == self::XML_LANG) {
+          $this->rdf_parser["top"]["xml_lang"] = $attribute_value;
+        }
+      }
+      elseif ($attribute_namespace_uri) {
+        $this->rdf_parser["top"]["has_property_attributes"] = true;
+      }
+    }
+
+    // this isn't allowed by the M&S but I think it should be
+    if ($statement_id && $resource) {
+      $this->_report_warning("rdf:ID and rdf:resource are mutually exclusive");
+      return;
+    }
+
+    if ($statement_id) {
+      $this->_resolve_id($statement_id, $buffer, strlen($buffer));
+      $this->rdf_parser["top"]["statement_id"] = $buffer;
+    }
+
+    if ($parse_type) {
+      if ($resource) {
+        $this->_report_warning("property elements with rdf:parseType do not allow rdf:resource");
+        return;
+      }
+
+      if ($bag_id) {
+        $this->_report_warning("property elements with rdf:parseType do not allow rdf:bagID");
+        return;
+      }
+
+      if ($this->rdf_parser["top"]["has_property_attributes"]) {
+        $this->_report_warning("property elements with rdf:parseType do not allow property attributes");
+        return;
+      }
+
+      if ($attribute_value == self::RDF_PARSE_TYPE_RESOURCE) {
+        $this->_generate_anonymous_uri($buffer, strlen($buffer));
+
+        // since we are sure that this is now a resource property we can report it
+        $this->_report_statement(
+          $this->rdf_parser["top"]["parent"]["subject_type"],
+          $this->rdf_parser["top"]["parent"]["subject"],
+          $this->rdf_parser["top"]["predicate"],
+          0,
+          self::RDF_OBJECT_TYPE_RESOURCE,
+          $buffer,
+          self::EMPTY_STRING,
+          $this->rdf_parser["top"]["parent"]["bag_id"],
+          $this->rdf_parser["top"]["parent"]["statements"],
+          $statement_id
+        );
+
+        $this->_push_element();
+
+        $this->rdf_parser["top"]["state"] = self::IN_PROPERTY_PARSE_TYPE_RESOURCE;
+        $this->rdf_parser["top"]["subject_type"] = self::RDF_SUBJECT_TYPE_ANONYMOUS;
+        $this->rdf_parser["top"]["subject"] = $buffer;
+        $this->rdf_parser["top"]["bag_id"] = self::EMPTY_STRING;
+      }
+      else {
+        $this->_report_statement(
+          $this->rdf_parser["top"]["parent"]["subject_type"],
+          $this->rdf_parser["top"]["parent"]["subject"],
+          $this->rdf_parser["top"]["predicate"],
+          0,
+          self::RDF_OBJECT_TYPE_XML,
+          self::EMPTY_STRING,
+          self::EMPTY_STRING,
+          $this->rdf_parser["top"]["parent"]["bag_id"],
+          $this->rdf_parser["top"]["parent"]["statements"],
+          $statement_id
+        );
+
+        $this->rdf_parser["top"]["state"] = self::IN_PROPERTY_PARSE_TYPE_LITERAL;
+        $this->_report_start_parse_type_literal();
+      }
+    }
+    elseif ($resource || $bag_id || $this->rdf_parser["top"]["has_property_attributes"]) {
+      if ($resource != self::EMPTY_STRING) {
+        $subject_type = self::RDF_SUBJECT_TYPE_URI;
+        $this->_resolve_uri_reference($this->rdf_parser["base_uri"], $resource, $buffer, strlen($buffer));
+      }
+      else {
+        $subject_type = self::RDF_SUBJECT_TYPE_ANONYMOUS;
+        $this->_generate_anonymous_uri($buffer, strlen($buffer));
+      }
+
+      $this->rdf_parser["top"]["state"] = self::IN_PROPERTY_EMPTY_RESOURCE;
+
+      // since we are sure that this is now a resource property we can report it.
+      $this->_report_statement(
+        $this->rdf_parser["top"]["parent"]["subject_type"],
+        $this->rdf_parser["top"]["parent"]["subject"],
+        $this->rdf_parser["top"]["predicate"],
+        $this->rdf_parser["top"]["ordinal"],
+        self::RDF_OBJECT_TYPE_RESOURCE,
+        $buffer,
+        self::EMPTY_STRING,
+        $this->rdf_parser["top"]["parent"]["bag_id"],
+        $this->rdf_parser["top"]["parent"]["statements"],
+        self::EMPTY_STRING
+      ); // should we allow IDs?
+
+      if ($bag_id) {
+        $this->_resolve_id($bag_id, $buffer, strlen($buffer));
+        $this->rdf_parser["top"]["bag_id"] = $buffer;
+      }
+
+      if ($this->rdf_parser["top"]["has_property_attributes"]) {
+        $this->_handle_property_attributes(
+          $subject_type,
+          $buffer,
+          $attributes,
+          $this->rdf_parser["top"]["xml_lang"],
+          $this->rdf_parser["top"]["bag_id"],
+          $this->rdf_parser["top"]["statements"]
+        );
+      }
+    }
+  }
+
+  private function _start_element_handler($parser, $name, $attributes) {
+    $buffer = self::EMPTY_STRING;
+
+    $namespace_uri = self::EMPTY_STRING;
+    $local_name = self::EMPTY_STRING;
+
+    $this->_push_element();
+
+    $this->_split_name($name, $buffer, strlen($buffer) , $namespace_uri, $local_name);
+
+    switch ($this->rdf_parser["top"]["state"]) {
+      case self::IN_TOP_LEVEL:
+        if (self::RDF_NAMESPACE_URI . self::NAMESPACE_SEPARATOR_STRING . self::RDF_RDF == $name) {
+          $this->rdf_parser["top"]["state"] = self::IN_RDF;
+        }
+        else {
+          $this->_report_start_element($name, $attributes);
+        }
+      break;
+      case self::IN_RDF:
+        $this->rdf_parser["top"]["state"] = self::IN_DESCRIPTION;
+        $this->_handle_resource_element($namespace_uri, $local_name, $attributes, self::EMPTY_STRING);
+      break;
+      case self::IN_DESCRIPTION:
+      case self::IN_PROPERTY_PARSE_TYPE_RESOURCE:
+        $this->rdf_parser["top"]["state"] = self::IN_PROPERTY_UNKNOWN_OBJECT;
+        $this->_handle_property_element($namespace_uri, $local_name, $attributes);
+      break;
+      case self::IN_PROPERTY_UNKNOWN_OBJECT:
+        /* if we're in a property with an unknown object type and we encounter
+         an element, the object must be a resource, */
+        $this->rdf_parser["top"]["data"] = self::EMPTY_STRING;
+        $this->rdf_parser["top"]["parent"]["state"] = self::IN_PROPERTY_RESOURCE;
+        $this->rdf_parser["top"]["state"] = self::IN_DESCRIPTION;
+        $this->_handle_resource_element(
+          $namespace_uri,
+          $local_name,
+          $attributes,
+          $this->rdf_parser["top"]["parent"]
+        );
+      break;
+      case self::IN_PROPERTY_LITERAL:
+        $this->_report_warning("no markup allowed in literals");
+      break;
+      case self::IN_PROPERTY_PARSE_TYPE_LITERAL:
+        $this->rdf_parser["top"]["state"] = self::IN_XML;
+        /* fall through */
+      case self::IN_XML:
+        $this->_report_start_element($name, $attributes);
+      break;
+      case self::IN_PROPERTY_RESOURCE:
+        $this->_report_warning("only one element allowed inside a property element");
+      break;
+      case self::IN_PROPERTY_EMPTY_RESOURCE:
+        $this->_report_warning("no content allowed in property with rdf:resource, rdf:bagID, or property attributes");
+      break;
+      case self::IN_UNKNOWN:
+      break;
+    }
+  }
+
+  /*
+  this is only called when we're in the self::IN_PROPERTY_UNKNOWN_OBJECT state.
+  the only time we won't know what type of object a statement has is
+  when we encounter property statements without property attributes or
+  content:
+  
+      <foo:property />
+      <foo:property ></foo:property>
+      <foo:property>    </foo:property>
+  
+  notice that the state doesn't switch to self::IN_PROPERTY_LITERAL when
+  there is only whitespace between the start and end tags. this isn't
+  a very useful statement since the object is anonymous and can't
+  have any statements with it as the subject but it is allowed.
+  */
+
+  private function _end_empty_resource_property() {
+    $buffer = self::EMPTY_STRING;
+
+    $this->_generate_anonymous_uri($buffer, strlen($buffer));
+
+    $this->_report_statement(
+      $this->rdf_parser["top"]["parent"]["subject_type"],
+      $this->rdf_parser["top"]["parent"]["subject"],
+      $this->rdf_parser["top"]["predicate"],
+      $this->rdf_parser["top"]["ordinal"],
+      self::RDF_OBJECT_TYPE_RESOURCE,
+      $buffer, $this->rdf_parser["top"]["xml_lang"],
+      $this->rdf_parser["top"]["parent"]["bag_id"],
+      $this->rdf_parser["top"]["parent"]["statements"],
+      $this->rdf_parser["top"]["statement_id"]
+    );
+  }
+
+  /*
+  property elements with text only as content set the state to
+  self::IN_PROPERTY_LITERAL. as character data is received from expat,
+  it is saved in a buffer and reported when the end tag is
+  received.
+  */
+  private function _end_literal_property() {
+    if (!isset($this->rdf_parser["top"]["statement_id"])) {
+      $this->rdf_parser["top"]["statement_id"] = self::EMPTY_STRING;
+    }
+    if (!isset($this->rdf_parser["top"]["parent"]["subject_type"])) {
+      $this->rdf_parser["top"]["parent"]["subject_type"] = self::EMPTY_STRING;
+    }
+    if (!isset($this->rdf_parser["top"]["parent"]["subject"])) {
+      $this->rdf_parser["top"]["parent"]["subject"] = self::EMPTY_STRING;
+    }
+    if (!isset($this->rdf_parser["top"]["parent"]["bag_id"])) {
+      $this->rdf_parser["top"]["parent"]["bag_id"] = self::EMPTY_STRING;
+    }
+    if (!isset($this->rdf_parser["top"]["parent"]["statements"])) {
+      $this->rdf_parser["top"]["parent"]["statements"] = 0;
+    }
+    if (!isset($this->rdf_parser["top"]["predicate"])) {
+      $this->rdf_parser["top"]["predicate"] = self::EMPTY_STRING;
+    }
+    if (!isset($this->rdf_parser["top"]["ordinal"])) {
+      $this->rdf_parser["top"]["ordinal"] = 0;
+    }
+    $this->_report_statement(
+      $this->rdf_parser["top"]["parent"]["subject_type"],
+      $this->rdf_parser["top"]["parent"]["subject"],
+      $this->rdf_parser["top"]["predicate"],
+      $this->rdf_parser["top"]["ordinal"],
+      self::RDF_OBJECT_TYPE_LITERAL,
+      $this->rdf_parser["top"]["data"],
+      $this->rdf_parser["top"]["xml_lang"],
+      $this->rdf_parser["top"]["parent"]["bag_id"],
+      $this->rdf_parser["top"]["parent"]["statements"],
+      $this->rdf_parser["top"]["statement_id"]
+    );
+  }
+
+  private function _end_element_handler($parser, $name) {
+
+    switch ($this->rdf_parser["top"]["state"]) {
+      case self::IN_TOP_LEVEL:
+        /* fall through */
+      case self::IN_XML:
+        $this->_report_end_element($name);
+      break;
+      case self::IN_PROPERTY_UNKNOWN_OBJECT:
+        $this->_end_empty_resource_property();
+      break;
+      case self::IN_PROPERTY_LITERAL:
+        $this->_end_literal_property();
+      break;
+      case self::IN_PROPERTY_PARSE_TYPE_RESOURCE:
+        $this->_pop_element();
+      break;
+      case self::IN_PROPERTY_PARSE_TYPE_LITERAL:
+        $this->_report_end_parse_type_literal();
+      break;
+      case self::IN_RDF:
+      case self::IN_DESCRIPTION:
+      case self::IN_PROPERTY_RESOURCE:
+      case self::IN_PROPERTY_EMPTY_RESOURCE:
+      case self::IN_UNKNOWN:
+      break;
+    }
+
+    $this->_pop_element();
+  }
+
+  private function _character_data_handler($parser, $s) {
+    $len = strlen($s);
+    switch ($this->rdf_parser["top"]["state"]) {
+      case self::IN_PROPERTY_LITERAL:
+      case self::IN_PROPERTY_UNKNOWN_OBJECT:
+        if (isset($this->rdf_parser["top"]["data"])) {
+          $n = strlen($this->rdf_parser["top"]["data"]);
+          $this->rdf_parser["top"]["data"] .= $s;
+
+        }
+        else {
+          $this->rdf_parser["top"]["data"] = $s;
+        }
+
+        if ($this->rdf_parser["top"]["state"] == self::IN_PROPERTY_UNKNOWN_OBJECT) {
+          /* look for non-whitespace */
+          for ($i = 0;(($i < $len) && (preg_match("/ |\n|\t/", $s[$i])));$i++);
+          $i++;
+          /* if we found non-whitespace, this is a literal */
+          if ($i <= $len) {
+            $this->rdf_parser["top"]["state"] = self::IN_PROPERTY_LITERAL;
+          }
+        }
+
+        break;
+      case self::IN_TOP_LEVEL:
+      case self::IN_PROPERTY_PARSE_TYPE_LITERAL:
+      case self::IN_XML:
+        $this->_report_character_data($s, strlen($s));
+        break;
+      case self::IN_RDF:
+      case self::IN_DESCRIPTION:
+      case self::IN_PROPERTY_RESOURCE:
+      case self::IN_PROPERTY_EMPTY_RESOURCE:
+      case self::IN_PROPERTY_PARSE_TYPE_RESOURCE:
+      case self::IN_UNKNOWN:
+        break;
+    }
+  }
+}
+
+?>