Source for file N3Parser.php

Documentation is available at N3Parser.php

  1. <?php
  2.  
  3. // ----------------------------------------------------------------------------------
  4. // Class: N3Parser
  5. // ----------------------------------------------------------------------------------
  6.  
  7.  
  8. /**
  9.  * PHP Notation3 Parser
  10.  * 
  11.  * This parser can parse a subset of n3, reporting triples to a callback function
  12.  * or constructing a RAP Model ( http://www.wiwiss.fu-berlin.de/suhl/bizer/rdfapi )
  13.  * 
  14.  * Supported N3 features:
  15.  * <ul>
  16.  *   <li>Standard things, repeated triples ( ; and , ), blank nodes using [ ], self-reference ('<>')</li>
  17.  *   <li>@prefix mappings</li>
  18.  *   <li>= maps to owl#sameAs</li>
  19.  *   <li>a maps to rdf-syntax-ns#type</li>
  20.  *   <li>Literal datytype- and xmlLanguageTag support
  21.  * </ul>
  22.  * Un-supported N3 Features include:
  23.  * <ul>
  24.  *   <li>Reification using { }</li>
  25.  *   <li>. and ^ operators for tree traversal</li>
  26.  *   <li>Any log operators, like log:forAll etc.</li>
  27.  * </ul>
  28.  *
  29.  * This parser is based on n3.py from Epp released 2nd March, 2002.
  30.  * by Sean B. Palmer
  31.  * ( http://infomesh.net/2002/eep/20020302-013802/n3.py )
  32.  * 
  33.  * This parser is released under the GNU GPL license.
  34.  * ( http://www.gnu.org/licenses/gpl.txt )
  35.  * 
  36.  *
  37.  *
  38.  * @author Sean B. Palmer <sean@mysterylights.com>, Gunnar AA. Grimnes <ggrimnes@csd.abdn.ac.uk>, Daniel Westphal <mail@d-westphal.de>
  39.  * @version $Id: fsource_syntax__syntaxN3Parser.php.html,v 1.10 2006/06/26 12:34:18 tgauss Exp $
  40.  * @package syntax
  41.  * @access public
  42.  ***/
  43.  
  44. class N3Parser extends Object {
  45.  
  46.  
  47.   /* ==================== Variables ==================== */
  48.  
  49.   var $Tokens;
  50.   var $bNode;
  51.   var $RDF_NS, $DAML_NS, $OWL_NS;
  52.   var $debug;
  53.   var $parseError;
  54.   var $parsedNamespaces = array();
  55.  
  56.   /* ==================== Public Methods ==================== */
  57.  
  58.   /** 
  59.    * Constructor
  60.    * @access public
  61.    ***/
  62.   function N3Parser() { 
  63.     //Regular expressions:
  64.      $Name = '[A-Za-z0-9_@\.]+[^\.,;\[\] ]*';
  65.      $URI = '<[^> ]*>';
  66.      $bNode = '_:'.$Name;
  67.      $Univar = '\?'.$Name;
  68.      $QName = '(?:[A-Za-z][A-Za-z0-9_@\.]*)?:'.$Name;
  69.      $Literal = '"(\\\"|[^"])*"'; # '"(?:\\"|[^"])*"'
  70. //   $Literal = '"[^"\\\\]*(?:\\.\\[^"\\]*)*"'; # '"(?:\\"|[^"])*"'
  71.      $LangTag = '@[A-Za-z\-]*[^ \^\.\;\,]';
  72.      $Datatype = '(\^\^)[^ ,\.;)]+';
  73.      $Datatype_URI = '(\^\^)'.$URI;  
  74.      //     $LLiteral = '"""[^"\\\\]*(?:(?:.|"(?!""))[^"\\\\]*)*"""';
  75.      $LLiteral = '"""[^"\\\\]*(?:(?:\\\\.|"(?!""))[^"\\\\]*)*"""';
  76.      //          '"""[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""'
  77.      $Comment = '# .*$';
  78.      $Prefix = '(?:[A-Za-z][A-Za-z0-9_]*)?:';
  79.      $PrefixDecl = '@prefix';
  80.      $WS = '[ \t]';
  81.      $this->RDF_NS = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; # for 'a' keyword
  82.      $this->DAML_NS = 'http://www.daml.org/2001/03/daml+oil#'; # for '=' keyword
  83.      $this->OWL_NS = 'http://www.w3.org/2002/07/owl#';
  84.  
  85.      //     $t = array( $LLiteral, $URI); //, $Literal, $PrefixDecl, $QName, $bNode, $Prefix,     
  86.      //        $Univar, 'a', '{', '}', '\(', '\)', '\[', '\]', ',', ';', '\.', $WS, $Comment);
  87.      $t = array( $Datatype_URI,$Datatype,$LLiteral, $URI, $Literal, $PrefixDecl, $QName, $bNode, $Prefix, $Univar, 'a','=', '{', '}', '\(', '\)', '\[', '\]', ',', ';', '\.', $WS, $Comment,$LangTag);
  88.      $this->Tokens="/(".join($t,"|").")/m";
  89.  
  90.      $this->bNode=0;
  91.      $this->debug=0;
  92.      $this->bNodeMap = array();
  93.      $this->FixBnodes = FIX_BLANKNODES;
  94.      $this->parseError=false;
  95.   }
  96.   
  97.  
  98.   /** 
  99.    * Sets, if BlankNode labels should be replaced by the generic label from the constants.php file
  100.    * default is "false" -> the used label in n3 is parsed to the model
  101.    * @param boolean 
  102.    * @access public
  103.    ***/
  104.   function setFixBnodes($set) {
  105.  
  106.       if (($set===true) OR ($set===false)) $this->FixBnodes = $set;
  107.   }
  108.   
  109.   
  110.   /** 
  111.    * This parses a N3 string and prints out the triples
  112.    * @param string $s 
  113.    * @access public
  114.    ***/
  115.   function parse($s) {
  116.     //   """Get a string, tokenize, create list, convert to Eep store."""
  117.     $stat=$this->n3tolist($s);
  118.     foreach ( $stat as $t) { 
  119.  
  120.       if (count($t)>3) {           
  121.         $object=$t[2];
  122.  
  123.         for ($i = 3; $i < 5; $i++){
  124.           if ($t[$i][0]=='@')$object.=$t[$i];
  125.           if (substr($t[$i],0,2)=='^^')$object.=$t[$i];                            
  126.         };
  127.       } else {$object=$t[2];};
  128.          
  129.       print '('.$t[0].', '.$t[1].', '.$object.")\n";
  130.  
  131.     }
  132.     //   return [[eep.Article(t[0]), eep.Article(t[1]), eep.Article(t[2])] 
  133.     //              for t in n3tolist(s)]
  134.   }
  135.  
  136.   
  137.   /** 
  138.    * This parses a N3 string and calls func($subject, $predicate, $object) with each trioke
  139.    * @param string $s 
  140.    * @param string $func 
  141.    * @access public
  142.    ***/
  143.   function uparse($s,$func) {
  144.     //   """Get a string, tokenize, create list, convert to Eep store."""
  145.     $stat=$this->n3tolist($s);
  146.     foreach ( $stat as $t) { 
  147.  
  148.         if (count($t)>3) {           
  149.         $object=$t[2];
  150.  
  151.         for ($i = 3; $i < 5; $i++){
  152.           if ($t[$i][0]=='@')$object.=$t[$i];
  153.           if (substr($t[$i],0,2)=='^^')$object.=$t[$i];                            
  154.         };
  155.       } else {$object=$t[2];};
  156.         //    print "(".$t[0].", ".$t[1].", ".$t[2].")";
  157.       
  158.       $func($t[0],$t[1],$object);
  159.     }
  160.     //   return [[eep.Article(t[0]), eep.Article(t[1]), eep.Article(t[2])] 
  161.     //              for t in n3tolist(s)]
  162.   }
  163.  
  164.  
  165.   /** 
  166.    * This parses a N3 string and returns a memmodel
  167.    * @param string $s 
  168.    * @access public
  169.    * @return object Model 
  170.    ***/
  171.  
  172.   function parse2model($s,$model = false) {
  173.     if($model == false){
  174.         $m=new MemModel();
  175.     }else{
  176.         $m=$model;
  177.     }
  178.     //   """Get a string, tokenize, create list, convert to Eep store."""
  179.     $stat=$this->n3tolist($s);
  180.  
  181.     foreach ( $stat as $t) { 
  182.       $s=$this->toRDFNode($t[0],$t);
  183.       $p=$this->toRDFNode($t[1],$t);
  184.       $o=$this->toRDFNode($t[2],$t);
  185.           
  186.        $new_statement= new Statement($s,$p,$o);     
  187.  
  188.       $m->add($new_statement);
  189.       //    print "(".$t[0].", ".$t[1].", ".$t[2].")";
  190.     }
  191.     //   return [[eep.Article(t[0]), eep.Article(t[1]), eep.Article(t[2])] 
  192.     //              for t in n3tolist(s)]
  193.     $m->addParsedNamespaces($this->parsedNamespaces);
  194.     return $m;
  195.   }
  196.  
  197. /**
  198.  * Generate a new MemModel from an URI or file.
  199.  *
  200.  * @access    public
  201.  * @param $path 
  202.  * @throws PhpError
  203.  * @return object MemModel 
  204.  */
  205.   function & generateModel($path,$dummy=false,$model=false) {
  206.  
  207.     $handle = fopen($path,'r') or die("N3 Parser: Could not open File: '$path' - Stopped parsing.");
  208.     $done=false;
  209.     $input="";
  210.     while(!$done)
  211.     {
  212.       $input .= fread( $handle, 512 );
  213.       $done = feof($handle);
  214.       
  215.     }; 
  216.  
  217.   
  218.     fclose($handle);
  219.  
  220.     return $this->parse2model($input,$model);
  221.   }
  222.   
  223.   
  224.   /* ==================== Private Methods from here ==================== */
  225.  
  226.   //  General list processing functions
  227.  
  228. /**
  229.  * Returns FALSE if argument is a whitespace character
  230.  * @access private
  231.  * @param string $s 
  232.  ***/
  233.   function isWS($s) { 
  234.     return !preg_match('/^(#.*|\s*)$/', $s);
  235.   }
  236.  
  237.  
  238.  
  239.   /** 
  240.    * Returns true if the string is not a comment
  241.    * @access private
  242.    * @param string $s 
  243.    * @returns boolean
  244.    ***/
  245.   function notComment($s) {
  246.     if ($s=="") return false; 
  247.     $N3Comment = '^[ \t]*\#';
  248.   
  249.     if (ereg($N3Comment,$s)) return false;
  250.     else return true;
  251.   }
  252.  
  253.   /**
  254.    * Removes all whitespace tokens from list
  255.    * @access private
  256.    * @param array $list 
  257.    ***/
  258.   function filterWs($list) {
  259.     //    var_dump($list);
  260.     //  """Filter whitespace from a list."""
  261.  
  262.     return array_filter($list, array($this,"isWS"));
  263.   }
  264.   
  265. /**
  266. * converts a string to its unicode NFC form (e.g. \uHHHH or \UHHHHHHHH).
  267. * 
  268. * @param String $str 
  269. * @return String 
  270. * @access private
  271. *
  272. */
  273. function str2unicode_nfc($str=""){
  274.     $result="";
  275.     /* try to detect encoding */
  276.     $tmp=str_replace("?", "", $str);
  277.     if(strpos(utf8_decode($tmp), "?")===false){
  278.         $str=utf8_decode($str);
  279.     }
  280.     for($i=0,$i_max=strlen($str);$i<$i_max;$i++){
  281.         $nr=0;/* unicode dec nr */
  282.         /* char */
  283.         $char=$str[$i];
  284.         /* utf8 binary */
  285.         $utf8_char=utf8_encode($char);
  286.         $bytes=strlen($utf8_char);
  287.         if($bytes==1){
  288.             /* 0####### (0-127) */
  289.             $nr=ord($utf8_char);
  290.         }
  291.         elseif($bytes==2){
  292.             /* 110##### 10###### = 192+x 128+x */
  293.             $nr=((ord($utf8_char[0])-192)*64) + (ord($utf8_char[1])-128);
  294.         }
  295.         elseif($bytes==3){
  296.             /* 1110#### 10###### 10###### = 224+x 128+x 128+x */
  297.             $nr=((ord($utf8_char[0])-224)*4096) + ((ord($utf8_char[1])-128)*64) + (ord($utf8_char[2])-128);
  298.         }
  299.         elseif($bytes==4){
  300.             /* 1111#### 10###### 10###### 10###### = 240+x 128+x 128+x 128+x */
  301.             $nr=((ord($utf8_char[0])-240)*262144) + ((ord($utf8_char[1])-128)*4096) + ((ord($utf8_char[2])-128)*64) + (ord($utf8_char[3])-128);
  302.         }
  303.         /* result (see http://www.w3.org/TR/rdf-testcases/#ntrip_strings) */
  304.         if($nr<9){/* #x0-#x8 (0-8) */
  305.             $result.="\\u".sprintf("%04X",$nr);
  306.         }
  307.         elseif($nr==9){/* #x9 (9) */
  308.             $result.='\t';
  309.         }
  310.         elseif($nr==10){/* #xA (10) */
  311.             $result.='\n';
  312.         }
  313.         elseif($nr<13){/* #xB-#xC (11-12) */
  314.             $result.="\\u".sprintf("%04X",$nr);
  315.         }
  316.         elseif($nr==13){/* #xD (13) */
  317.             $result.='\t';
  318.         }
  319.         elseif($nr<32){/* #xE-#x1F (14-31) */
  320.             $result.="\\u".sprintf("%04X",$nr);
  321.         }
  322.         elseif($nr<34){/* #x20-#x21 (32-33) */
  323.             $result.=$char;
  324.         }
  325.         elseif($nr==34){/* #x22 (34) */
  326.             $result.='\"';
  327.         }
  328.         elseif($nr<92){/* #x23-#x5B (35-91) */
  329.             $result.=$char;
  330.         }
  331.         elseif($nr==92){/* #x5C (92) */
  332.             $result.='\\';
  333.         }
  334.         elseif($nr<127){/* #x5D-#x7E (93-126) */
  335.             $result.=$char;
  336.         }
  337.         elseif($nr<65536){/* #x7F-#xFFFF (128-65535) */
  338.             $result.="\\u".sprintf("%04X",$nr);
  339.         }
  340.         elseif($nr<1114112){/* #x10000-#x10FFFF (65536-1114111) */
  341.             $result.="\\U".sprintf("%08X",$nr);
  342.         }
  343.         else{
  344.             /* other chars are not defined => ignore */
  345.         }
  346.     }
  347.     return $result;
  348. }
  349.  
  350.   
  351.  
  352.   /**
  353.    * Gets a slice of an array.
  354.    * Returns the wanted slice, as well as the remainder of the array.
  355.    * e.g. getSpan(['p', 'q', 'r'], 1, 2) gives (['q'], ['p', 'r'])
  356.    * @return array 
  357.    * @access private
  358.    * @param array $list 
  359.    * @param integer $start 
  360.    * @param integer $end 
  361.    ***/
  362.   function getSpan($list, $start, $end) {
  363.     
  364.     $pre=array_slice($list, 0, $start);
  365.     $post=array_slice($list, $end);
  366.  
  367.     return array(array_slice($list, $start,$end-$start),$this->array_concat($pre,$post));
  368.   }
  369.  
  370.  
  371.   /** 
  372.    * Concatenates two arrays
  373.    * @param array $a 
  374.    * @param array $b 
  375.    * @returns array
  376.    * @access private
  377.    ***/
  378.   function array_concat($a, $b) { 
  379.     array_splice($a,count($a),0,$b);
  380.     return $a;
  381.   }
  382.  
  383.   /**
  384.    * Returns an array with all indexes where item appears in list
  385.    * @param array $list 
  386.    * @param string $item 
  387.    * @returns array
  388.    * @access private
  389.    ***/
  390.   function posns($list, $item) { 
  391.     $res=array(); 
  392.     $i=0;
  393.     foreach ( $list as $k=>$v) {     
  394.       if ($v === $item ) $res[]=$i;
  395.       $i++;
  396.     }
  397.     $res[]=$i;
  398.     return $res;
  399.   }
  400.  
  401.  
  402.   /* More N3 specific functions */
  403.  
  404.   /** 
  405.    * Returns a list of tokens
  406.    * @param string $s 
  407.    * @returns array
  408.    * @access private
  409.    ***/
  410.   function toke($s) {
  411.  
  412.     //    print "$s\n";
  413.     //   """Notation3 tokenizer. Takes in a string, returns a raw token list."""
  414.     if (strlen($s) == 0) die('Document has no content!');
  415.  
  416.     $s=str_replace("\r\n","\n",$s);
  417.     $s=str_replace("\r","\n",$s);
  418.  
  419.  
  420.     //$lines=explode("\n",$s);
  421.  
  422.     //$reallines=array_filter($lines, array($this, "notComment"));
  423.     //    print "LINES: ".join($reallines, " ")." :LINES\n";
  424.     //array_walk($reallines, array($this, "trimLine"));
  425.     //$res=array();
  426.  
  427.     //    foreach ($reallines as $l) {    
  428.     //preg_match_all($this->Tokens, $l, $newres);
  429.     //$res=$this->array_concat($res,$newres[0]);
  430.     //}
  431.  
  432.     $res=array();
  433.     preg_match_all($this->Tokens, $s, $newres);
  434.  
  435.     $res=$this->array_concat($res, array_map('trim', $newres[0]));
  436.   
  437.     return $res;
  438.   }
  439.  
  440.   /** 
  441.    * Returns a list with the elements between start and end as one quoted string
  442.    * e.g. listify(["a","b","c","d"],1,2) => ["a","b c", "d"]
  443.    * @param array $list 
  444.    * @param integer $start 
  445.    * @param integer $end 
  446.    * @returns array
  447.    * @access private
  448.    ***/
  449.   function listify($list, $start, $end) {
  450.  
  451.     //Re-form a list, merge elements start->end into one quoted element
  452.     //Start and end are offsets...
  453.  
  454.     $l=$end-$start;
  455.  
  456.     $s=array_slice($list, 0, $start);
  457.     $m=array_slice($list, $start,$l);
  458.     $e=array_slice($list, $end);
  459.   
  460.     //  array_push($s,"\"".join($m," ")."\"");
  461.     array_push($s,$m);
  462.   
  463.     return $this->array_concat($s,$e);
  464.   }
  465.  
  466.   /**
  467.    * Returns an array with prefixes=>namespace mappings
  468.    * @param array $list 
  469.    * @access private
  470.    * @returns array
  471.    ***/
  472.   function getPrefixes($list) {
  473.  
  474.     $prefixes=array();
  475.     $ns=1;
  476.     $name=2;
  477.     foreach ($list as $l) { 
  478.       if ($l=='@prefix') { 
  479.     //   while '@prefix' in list {
  480.       
  481.     $pos=current($list);
  482.     //pos = list.index('@prefix')
  483.     $r = $this->getSpan($list, $pos, ($pos+4)); # processes the prefix tokens
  484.     $binding=$r[0];
  485.     $list=$r[1];
  486.     $prefixes[$binding[$ns]] = substr($binding[$name],1,-1);
  487.     $this->parsedNamespaces[substr($binding[$name],1,-1)] = substr($binding[$ns],0,-1);
  488.       }
  489.     }
  490.  
  491.     if (count($prefixes)<1) $list= array_slice($list,0);
  492.     
  493.     return array($prefixes, $list);
  494.   }
  495.  
  496.   /**
  497.    * Callback function for replacing "a" elements with the right RDF uri.
  498.    * @param string $l 
  499.    * @access private
  500.    ***/
  501.   function replace_a_type(&$l,$p) {
  502.     if ($l=='a') $l='<'.$this->RDF_NS.'type>';
  503.   }
  504.  
  505.   /**
  506.    * Callback function for replacing "=" elements with the right DAML+OIL uri.
  507.    * @param string $l 
  508.    * @access private
  509.    ***/
  510.   function replace_equal(&$l,$p) {
  511.     if ($l=='=') $l='<'.$this->OWL_NS.'sameAs>';
  512.   }
  513.  
  514.   /**
  515.    * Callback function for replacing "this" elements with the right RDF uri.
  516.    * @param string $l 
  517.    * @access private
  518.    ***/
  519.   function replace_this($l,$p) {
  520.     if ($l=='this') $l='<urn:urn-n:this>';
  521.   }
  522.  
  523.   /**
  524.    * Applies stuff :)
  525.    * Expands namespace prefixes etc.
  526.    * @param array $prefixes 
  527.    * @param array $list 
  528.    * @returns $list
  529.    * @access private
  530.    ***/
  531.   function applyStuff($prefixes, $list) {
  532.  
  533.     array_walk($list, array($this, 'replace_a_type'));
  534.     array_walk($list, array($this, 'replace_equal'));
  535.     array_walk($list, array($this, 'replace_this'));
  536.  
  537.     for ($i=0;$i<count($list);$i++) { 
  538.       //   for i in range(len(list)) {
  539. //      if (!strstr('<_"?.;,{}[]()',$list[$i]{0})) {
  540.  
  541.  
  542. // if a <> resource occours, change it to the parsed filename or local URI + timestamp
  543.  
  544.         if ($list[$i]=='<>') {
  545.             if (!isset($path)) { 
  546.                 if (!isset($_SERVER['SERVER_ADDR'])) $_SERVER['SERVER_ADDR']='localhost';
  547.                 if (!isset($_SERVER['REQUEST_URI'])) $_SERVER['REQUEST_URI']='/rdfapi-php';
  548.                 $list[$i]='<http://'.$_SERVER['SERVER_ADDR'].$_SERVER['REQUEST_URI'].'#generate_timestamp_'.time().'>';
  549.                 
  550.           }else {$list[$i]='<'.$path.'>';};
  551.         };        
  552.  
  553.  
  554.         if ((!strstr('<_"?.;,{}[]()@',$list[$i]{0}))AND (substr($list[$i],0,3)!='^^<')) {
  555.       $_r= explode(":",$list[$i]);
  556.  
  557.  
  558.  
  559.  
  560.  
  561.     $ns=$_r[0].':';
  562.     $name=$_r[1];
  563.   
  564.     if (isset($prefixes[$ns])) $list[$i] = '<'.$prefixes[$ns].$name.'>';
  565.     else if (isset($prefixes[substr($ns,2)])) $list[$i] = '^^'.$prefixes[substr($ns,2)].$name.''; 
  566.   else {
  567.   #die('Prefix not declared:'.$ns);
  568.       $this->parseError=true;
  569.     trigger_error('Prefix not declared: '.$ns, E_USER_ERROR);
  570.     break;
  571.     
  572.     
  573.   }
  574.   
  575.       } else {       
  576.     if ($list[$i]{0} == '"') {  // Congratulations - it's a literal!
  577.       if (substr($list[$i],0,3) == '"""') {
  578.         if (substr($list[$i],-3,3) == '"""') { // A big literal...
  579.           $lit = substr($list[$i],3,-3);         
  580.           //          print "++$lit++";
  581.           $lit=str_replace('\n', '\\n',$lit);
  582.  
  583.           $lit=ereg_replace("[^\\]\"", "\\\"", $lit);
  584.  
  585.           $list[$i] = '"'.$lit.'"';
  586.         }
  587.         else { die ('Incorrect string formatting: '.substr($list[$i],-3,3)); }
  588.       } else {
  589.         if (strstr($list[$i],"\n")) die('Newline in literal: '+$list[$i]);
  590.       }
  591.     }
  592.       }
  593.     
  594.       if (substr($list[$i],0,2)=='^^') {
  595.         if ($list[$i][2]!='<'){$list[$i]='^^<'.substr($list[$i],2).'>';};
  596.       };
  597.  
  598.     
  599.     }
  600.  
  601.  
  602.     return $list;
  603.   }
  604.  
  605.   /** 
  606.    * Returns an array of triples extracted from the list of n3 tokens
  607.    * @param array $list 
  608.    * @returns array
  609.    * @access private
  610.    ***/
  611.   function getStatements($list) {
  612.  
  613.  
  614.     $statements = array();
  615.  
  616.     while (in_array('.', $list)) {
  617.       //  for($i=0;$i<count($list); $i++) {
  618.       //    if ($list[$i]==".") {
  619.       //   while '.' in list {
  620.       $pos=array_search('.',$list);
  621.  
  622.       $r=$this->getSpan($list, 0, $pos+1);    
  623.  
  624.       $statement=$r[0];
  625.       $list = $r[1];
  626.  
  627.       array_pop($statement);
  628.       $statements[]=$statement;
  629.     }
  630.  
  631.     return $statements;
  632.   }
  633.   
  634.   /** 
  635.    * Gets a list of triples with same subject
  636.    * e.g. :Gunnar :firstname "Gunnar" ; :lastname "Grimnes.
  637.    * @param array $list 
  638.    * @returns array
  639.    * @acces private
  640.    ***/
  641.   function getPovs($list) {
  642.     $povs = array();
  643.     while (in_array(';', $list)) {
  644.       $r=$this->posns($list,';');
  645.       $pos=array_slice($r,0,2);
  646.       $r = $this->getSpan($list, $pos[0], $pos[1]);
  647.       $pov=$r[0];
  648.       $list=$r[1];
  649.  
  650.       // skip lone semicolons, e.g. "<a> <b> <c> ; ."
  651.       if (count($pov) == 1) continue;
  652.  
  653.       $povs[]=array_slice($pov,1);
  654.     }
  655.  
  656.     return array($list, $povs);
  657.   }
  658.  
  659.   /** 
  660.    * Gets a list of triples with same predicate
  661.    * e.g. :Gunnar :likes "Cheese", "Wine".
  662.    * @access private
  663.    * @param array $list 
  664.    * @returns array
  665.    ***/
  666.   function getObjs($list) {
  667.  
  668.  
  669.     $objs = array();
  670.     while (in_array(",",$list)) {
  671.       $pos=array_search(",",$list);
  672.       //  for($i=0;$i<count($list); $i++) {
  673.       //    if ($list[$i]==",") {
  674.       //   while ',' in list {
  675.  
  676.  
  677.       $get_array_fields=2;
  678.       if (isset ($list[$pos+2])) { 
  679.           if (@$list[$pos+2][0]=='@') $get_array_fields++;
  680.         if (@$list[$pos+2][0]=='^') $get_array_fields++;
  681.       };
  682.       if (isset ($list[$pos+3])) { if (@$list[$pos+3][0]=='^') $get_array_fields++;};
  683.  
  684.  
  685.       $r=$this->getSpan($list, $pos, ($pos+$get_array_fields));
  686.  
  687.       $obj=$r[0];
  688.       if (!isset($obj[2])) $obj[2]=' ';
  689.       if (!isset($obj[3])) $obj[3]=' ';
  690.       
  691.       $list=$r[1];
  692.  
  693.      
  694.       $objs[]=$obj;
  695.  
  696.  
  697.     }
  698.   
  699.     return array($list, $objs);
  700.   }
  701.  
  702.   /**
  703.    * Does the real work, returns a list of subject, predicate, object triples.
  704.    * @param array $list 
  705.    * @returns array
  706.    * @access private
  707.    ***/
  708.   function statementize($list) {
  709.  
  710.     if (count($list) == 1 && preg_match("/_".BNODE_PREFIX."[0-9]+_/",$list[0])) { 
  711.     if ($this->debug) print "Ignored bNode exists statement. $list\n";
  712.     return array(); 
  713.     }
  714.  
  715.     
  716.     
  717.     if (count($list) == 3) return array($list);
  718.     if (count($list) < 3) die("Error: statement too short!");
  719.  
  720.     //Get all ; 
  721.     $r=$this->getPovs($list);
  722.     $spo=$r[0];
  723.     $po=$r[1];
  724.     $all=array();
  725.  
  726.  
  727.  
  728.     //      (spo, po), all = getPovs(list), []
  729.     $subject = $spo[0];
  730.     foreach ($po as $pop) {
  731.       //  for pop in po {
  732.       $r=$this->getObjs($pop);
  733.  
  734.       $myPo=$r[0];
  735.       $obj=$r[1];
  736.       //myPo, obj = getObjs(pop)
  737.  
  738.       if (!isset($myPo[2])) $myPo[2]=' ';
  739.       if (!isset($myPo[3])) $myPo[3]=' ';
  740.  
  741.     
  742.       $predicate = $myPo[0];
  743.       $all[]=array($subject,$predicate,$myPo[1],$myPo[2],$myPo[3]);
  744.       //    all.append([subject, predicate, myPo[1]])
  745.  
  746.        
  747.  
  748.       foreach ($obj as $o) $all[]=array($subject,$predicate, $o[1],$o[2],$o[3]);
  749.       //         for x in obj: all.append([subject, predicate, x])
  750.  
  751.     }
  752.  
  753.  
  754.  
  755.     $r = $this->getObjs($spo);
  756.     $spo=$r[0];
  757.  
  758.     $objs=$r[1];
  759.  
  760.     //spo, objs = getObjs(spo)
  761.     $subject=$spo[0];
  762.     $predicate=$spo[1];
  763.  
  764.     
  765.     if(!isset($spo[3])) $spo[3]=' ';     
  766.     if(!isset($spo[4])) $spo[4]=' ';     
  767.       
  768.     $all[]=array($subject, $predicate, $spo[2],$spo[3],$spo[4]);
  769.  
  770.     foreach ($objs as $obj) $all[]=array($subject, $predicate, $obj[1],$obj[2],$obj[3]);
  771.  
  772.     return $all;
  773.   }
  774.  
  775.   /**
  776.    * Makes lists of elements in list into a seperate array element.
  777.    * e.g. doLists(["a","b","[","c","]","d"], "[","]")=> ["a","b", ["c"], "d"]
  778.    * @param array $list 
  779.    * @param string $schar 
  780.    * @param string $echar 
  781.    * @returns array
  782.    * @access private
  783.    ***/
  784.   function doLists($list, $schar, $echar) {
  785.  
  786.     while (in_array($schar, $list)) {
  787.       //   while schar in list {
  788.       $ndict=array();
  789.       $nestingLevel=0;
  790.       $biggest=0;
  791.       for ($i=0;$i<count($list);$i++) {
  792.     if ($list[$i] == $schar) {
  793.       $nestingLevel += 1;
  794.       if (!in_array($nestingLevel, array_keys($ndict))) {
  795.         $ndict[$nestingLevel] = array(array($i));
  796.       } else { 
  797.         $ndict[$nestingLevel][]=array($i);
  798.       }
  799.     }
  800.     if ($list[$i] == $echar) {
  801.       if (!in_array($nestingLevel, array_keys($ndict))) {
  802.         $ndict[$nestingLevel]=array(array($i));
  803.       } else { 
  804.             $ndict[$nestingLevel][count($ndict[$nestingLevel])-1][]=$i;
  805.             $nestingLevel-= 1;
  806. # elif type(list[i]) == type([]) {
  807. #    list[i] = doLists(list[i], schar, echar)
  808.       }
  809.     }
  810.       }
  811.       foreach (array_keys($ndict) as $key) 
  812.     if ($key > $biggest)  $biggest = $key;
  813.  
  814.       $tol = $ndict[$biggest][0];
  815.       $list = $this->listify($list, $tol[0], ($tol[1]+1));
  816.     }
  817.     return $list;
  818.   }
  819.  
  820.   /** 
  821.    * Apply doLists for all different types of list.
  822.    * @param array 
  823.    * @returns array
  824.    * @access private
  825.    ***/
  826.   function listStuff($list) {
  827. # y, z = zip(['[', ']'], ['{', '}'], ['(', ')'])
  828. # return map(doLists, [list, list, list], y, z).pop()
  829.     $list = $this->doLists($list, '[', ']');
  830.     $list = $this->doLists($list, '{', '}');
  831.     return $this->doLists($list, '(', ')');
  832.   }
  833.  
  834.   /**
  835.    * Generates a new node id.
  836.    * @access private
  837.    * @returns string
  838.    ***/
  839.   function bnodeID() {
  840.   
  841.     $this->bNode++;
  842.     return "_".BNODE_PREFIX.$this->bNode."_";
  843.   }
  844.  
  845.   /** 
  846.    * This makes bNodes out of variables like _:a etc.
  847.    * @access private
  848.    * @param array $list 
  849.    * @returns array
  850.    ***/
  851.   function fixAnon($list) {
  852. //    $map=array();
  853.     for($i=0;$i<count($list);$i++) {
  854.       $l=$list[$i];
  855.       if (substr($l,0,2)=="_:") {
  856.       if (!isset($this->bNodeMap[$l])) {
  857.       $a=$this->bnodeID();
  858.       $this->bNodeMap[$l]=$a;
  859.     } else $a=$this->bNodeMap[$l];
  860.     $list[$i]=$a;
  861.       }
  862.     }
  863.     return $list;
  864.   }
  865.  
  866.   /**
  867.    * This makes [ ] lists into bnodes.
  868.    * @access private
  869.    * @param array $list 
  870.    * @return array 
  871.    ***/
  872.   function expandLists($list) {
  873.  
  874.     for($i=0;$i<count($list);$i++) {
  875.       if (is_array($list[$i])) {
  876.     if ( $list[$i][0]=='[' ) {
  877.       $bnode=$this->bnodeID();
  878.       $prop=$list[$i];
  879.       $list[$i]=$bnode;
  880.       $list[]=$bnode;
  881.       $list=$this->array_concat($list, array_slice($prop,1,-1));
  882.       $list[]='.';
  883.     }elseif($list[$i][0]=='(') {
  884.  
  885.         $rdfNil = '<'. RDF_NAMESPACE_URI . RDF_NIL .'>';
  886.         $rdfFirst = '<'. RDF_NAMESPACE_URI . RDF_FIRST .'>';
  887.         $rdfRest = '<'. RDF_NAMESPACE_URI . RDF_REST .'>';
  888.  
  889.         // local copy of list without "(" and ")"
  890.         $t_list = array_slice($list[$i], 1, -1);
  891.  
  892.         //prepare bnodes
  893.         $fromBnode = $this->bnodeID();
  894.         $toBnode = $this->bnodeID();
  895.  
  896.         //link first bnode into graph
  897.         $list[$i] = $fromBnode;
  898.  
  899.         $count = count($t_list);
  900.  
  901.         //loop through list, convert to RDF linked list
  902.         for ($idx = 0; $idx < $count; $idx++){
  903.  
  904.             // set rdf:first
  905.             $list[] = $fromBnode;
  906.             $list[] = $rdfFirst;
  907.             $list[] = $t_list[$idx];
  908.             $list[] = '.';
  909.  
  910.             // set rdf:rest (nil or next bnode)
  911.             if ($idx == $count - 1) {
  912.                 $list[] = $fromBnode;
  913.                 $list[] = $rdfRest;
  914.                 $list[] = $rdfNil;
  915.                 $list[] = '.';
  916.             }
  917.             else {
  918.                 $list[] = $fromBnode;
  919.                 $list[] = $rdfRest;
  920.                 $list[] = $toBnode;
  921.                 $list[] = '.';
  922.  
  923.                 $fromBnode = $toBnode;
  924.                 $toBnode = $this->bnodeID();
  925.             }
  926.         }
  927.     }
  928.     else {
  929.         die('Only [ ] and () lists are supported!');
  930.     }
  931.     }
  932.  
  933.     
  934.     }
  935.     return $list;
  936.   }
  937.  
  938.   /** 
  939.    * Main work-horse function. This converts a N3 string to a list of statements
  940.    * @param string $s 
  941.    * @returns array
  942.    * @access private
  943.    ***/
  944.   function n3tolist($s) {
  945.  
  946.     //   """Convert an N3 string into a list of triples as strings."""
  947.     $result = array();
  948.  
  949.    $t = $this->filterWs($this->toke($s)); # tokenize the stream, and filter whitespace tokens
  950.  
  951.     if ($this->debug) {
  952.       print "Filter WS:\n";
  953.       var_dump($t);
  954.     }
  955.     $r=$this->getPrefixes($t); # get the prefix directives, and add to a dict
  956.     $prefixes=$r[0];
  957.     $t=$r[1];
  958.     if ($this->debug) {
  959.       print "Prefixes:\n";
  960.       var_dump($prefixes);
  961.       print "***\n";
  962.       var_dump($t);
  963.     }
  964.     $t=$this->applyStuff($prefixes, $t);#apply prefixes, keywords, and string formatting 
  965.     if ($this->debug) {
  966.       print "Stuff applied:\n";
  967.       var_dump($t);
  968.     }
  969.  
  970.     $t=$this->fixAnon($t); # fix _:a anons
  971.     if ($this->debug) {
  972.       print "Fix anon:\n";
  973.       var_dump($t);
  974.     }
  975.     
  976.     $t = $this->listStuff($t); # apply list stuff: todo
  977.     if ($this->debug) {
  978.       print "Lists done:\n";
  979.       var_dump($t);
  980.     }
  981.     $t=$this->expandLists($t);
  982.     if ($this->debug) {
  983.       print "Lists applied:\n";
  984.       var_dump($t);
  985.     }
  986.     $t = $this->getStatements($t); # get all of the "statements" from the stream
  987.  
  988.     foreach ($t as $stat) {
  989.       $stats=$this->statementize($stat);
  990.  
  991.       foreach ($stats as $y) {
  992.     $result[]=$y;
  993.       }
  994.     }
  995.     //   for x in [statementize(stat) for stat in t] {
  996.     //      for y in x: result.append(y)
  997.     return $result;
  998.   }
  999.  
  1000.   /** 
  1001.    * Constructs a RAP RDFNode from URI/Literal/Bnode
  1002.    * @access private
  1003.    * @param string $s 
  1004.    * @returns object RDFNode
  1005.    ***/
  1006.   function toRDFNode($s,$state) {
  1007.     $ins=substr($s,1,-1);
  1008.     if ($s{0}=="\"") {
  1009.       $lang=NULL;
  1010.     
  1011.  
  1012.  
  1013.       if (count($state)>3) {           
  1014.  
  1015.  
  1016.         for ($i = 3; $i < count($state); $i++){
  1017.           if ($state[$i][0]=='@')$lang=substr($state[3],1);
  1018.           if (substr($state[$i],0,2)=='^^'){
  1019.             
  1020.             $dtype=substr($state[$i],2);
  1021.             if ($dtype[0]=='<') $dtype= substr($dtype,1,-1);
  1022.             
  1023.           };
  1024.           
  1025.         };
  1026.       };
  1027.       
  1028.     
  1029.      if(UNIC_RDF){
  1030.           $ins=$this->str2unicode_nfc($ins);
  1031.       }
  1032.       $new_Literal=new Literal($ins,$lang);
  1033.       if (isset($dtype)) $new_Literal->setDatatype($dtype);     
  1034.       return  $new_Literal;        
  1035.     };
  1036.  
  1037.     if (strstr($s,'_'.BNODE_PREFIX)) { 
  1038.         if (($this->FixBnodes) OR (!array_search($s,$this->bNodeMap))) {
  1039.             return new BlankNode($ins);
  1040.         } else {return new BlankNode(trim(substr(array_search($s,$this->bNodeMap),2)));
  1041.         };
  1042.     }
  1043.     
  1044.     return new Resource($ins); 
  1045.   }
  1046.  
  1047.  
  1048.   
  1049.   
  1050. } //end: N3Parser
  1051.  
  1052. ?>

Documentation generated on Mon, 26 Jun 2006 14:25:41 +0200 by phpDocumentor 1.3.0RC6