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===trueOR ($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_statementnew 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 ParserCould not open File: '$path' - Stopped parsing.");
  208.     $done=false;
  209.     $input="";
  210.     while(!$done)
  211.     {
  212.       $input .= fread$handle512 );
  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($listarray($this,"isWS"));
  263.   }
  264.   
  265. /**
  266. * converts a string to its unicode NFC form (e.g. \uHHHH or \UHHHHHHHH).
  267. @param String $str 
  268. @return String 
  269. @access private
  270. *
  271. */
  272. function str2unicode_nfc($str=""){
  273.     $result="";
  274.     /* try to detect encoding */
  275.     $tmp=str_replace("?"""$str);
  276.     if(strpos(utf8_decode($tmp)"?")===false){
  277.         $str=utf8_decode($str);
  278.     }
  279.     for($i=0,$i_max=strlen($str);$i<$i_max;$i++){
  280.         $nr=0;/* unicode dec nr */
  281.         /* char */
  282.         $char=$str[$i];
  283.         /* utf8 binary */
  284.         $utf8_char=utf8_encode($char);
  285.         $bytes=strlen($utf8_char);
  286.         if($bytes==1){
  287.             /* 0####### (0-127) */
  288.             $nr=ord($utf8_char);
  289.         }
  290.         elseif($bytes==2){
  291.             /* 110##### 10###### = 192+x 128+x */
  292.             $nr=((ord($utf8_char[0])-192)*64(ord($utf8_char[1])-128);
  293.         }
  294.         elseif($bytes==3){
  295.             /* 1110#### 10###### 10###### = 224+x 128+x 128+x */
  296.             $nr=((ord($utf8_char[0])-224)*4096((ord($utf8_char[1])-128)*64(ord($utf8_char[2])-128);
  297.         }
  298.         elseif($bytes==4){
  299.             /* 1111#### 10###### 10###### 10###### = 240+x 128+x 128+x 128+x */
  300.             $nr=((ord($utf8_char[0])-240)*262144((ord($utf8_char[1])-128)*4096((ord($utf8_char[2])-128)*64(ord($utf8_char[3])-128);
  301.         }
  302.         /* result (see http://www.w3.org/TR/rdf-testcases/#ntrip_strings) */
  303.         if($nr<9){/* #x0-#x8 (0-8) */
  304.             $result.="\\u".sprintf("%04X",$nr);
  305.         }
  306.         elseif($nr==9){/* #x9 (9) */
  307.             $result.='\t';
  308.         }
  309.         elseif($nr==10){/* #xA (10) */
  310.             $result.='\n';
  311.         }
  312.         elseif($nr<13){/* #xB-#xC (11-12) */
  313.             $result.="\\u".sprintf("%04X",$nr);
  314.         }
  315.         elseif($nr==13){/* #xD (13) */
  316.             $result.='\t';
  317.         }
  318.         elseif($nr<32){/* #xE-#x1F (14-31) */
  319.             $result.="\\u".sprintf("%04X",$nr);
  320.         }
  321.         elseif($nr<34){/* #x20-#x21 (32-33) */
  322.             $result.=$char;
  323.         }
  324.         elseif($nr==34){/* #x22 (34) */
  325.             $result.='\"';
  326.         }
  327.         elseif($nr<92){/* #x23-#x5B (35-91) */
  328.             $result.=$char;
  329.         }
  330.         elseif($nr==92){/* #x5C (92) */
  331.             $result.='\\';
  332.         }
  333.         elseif($nr<127){/* #x5D-#x7E (93-126) */
  334.             $result.=$char;
  335.         }
  336.         elseif($nr<65536){/* #x7F-#xFFFF (128-65535) */
  337.             $result.="\\u".sprintf("%04X",$nr);
  338.         }
  339.         elseif($nr<1114112){/* #x10000-#x10FFFF (65536-1114111) */
  340.             $result.="\\U".sprintf("%08X",$nr);
  341.         }
  342.         else{
  343.             /* other chars are not defined => ignore */
  344.         }
  345.     }
  346.     return $result;
  347. }
  348.  
  349.   
  350.  
  351.   /**
  352.    * Gets a slice of an array.
  353.    * Returns the wanted slice, as well as the remainder of the array.
  354.    * e.g. getSpan(['p', 'q', 'r'], 1, 2) gives (['q'], ['p', 'r'])
  355.    * @return array 
  356.    * @access private
  357.    * @param array $list 
  358.    * @param integer $start 
  359.    * @param integer $end 
  360.    ***/
  361.   function getSpan($list$start$end{
  362.     
  363.     $pre=array_slice($list0$start);
  364.     $post=array_slice($list$end);
  365.  
  366.     return array(array_slice($list$start,$end-$start),$this->array_concat($pre,$post));
  367.   }
  368.  
  369.  
  370.   /** 
  371.    * Concatenates two arrays
  372.    * @param array $a 
  373.    * @param array $b 
  374.    * @returns array
  375.    * @access private
  376.    ***/
  377.   function array_concat($a$b
  378.     array_splice($a,count($a),0,$b);
  379.     return $a;
  380.   }
  381.  
  382.   /**
  383.    * Returns an array with all indexes where item appears in list
  384.    * @param array $list 
  385.    * @param string $item 
  386.    * @returns array
  387.    * @access private
  388.    ***/
  389.   function posns($list$item
  390.     $res=array()
  391.     $i=0;
  392.     foreach $list as $k=>$v{     
  393.       if ($v === $item $res[]=$i;
  394.       $i++;
  395.     }
  396.     $res[]=$i;
  397.     return $res;
  398.   }
  399.  
  400.  
  401.   /* More N3 specific functions */
  402.  
  403.   /** 
  404.    * Returns a list of tokens
  405.    * @param string $s 
  406.    * @returns array
  407.    * @access private
  408.    ***/
  409.   function toke($s{
  410.  
  411.     //    print "$s\n";
  412.     //   """Notation3 tokenizer. Takes in a string, returns a raw token list."""
  413.     if (strlen($s== 0die('Document has no content!');
  414.  
  415.     $s=str_replace("\r\n","\n",$s);
  416.     $s=str_replace("\r","\n",$s);
  417.  
  418.  
  419.     //$lines=explode("\n",$s);
  420.  
  421.     //$reallines=array_filter($lines, array($this, "notComment"));
  422.     //    print "LINES: ".join($reallines, " ")." :LINES\n";
  423.     //array_walk($reallines, array($this, "trimLine"));
  424.     //$res=array();
  425.  
  426.     //    foreach ($reallines as $l) {    
  427.     //preg_match_all($this->Tokens, $l, $newres);
  428.     //$res=$this->array_concat($res,$newres[0]);
  429.     //}
  430.  
  431.     $res=array();
  432.     preg_match_all($this->Tokens$s$newres);
  433.  
  434.     $res=$this->array_concat($resarray_map('trim'$newres[0]));
  435.   
  436.     return $res;
  437.   }
  438.  
  439.   /** 
  440.    * Returns a list with the elements between start and end as one quoted string
  441.    * e.g. listify(["a","b","c","d"],1,2) => ["a","b c", "d"]
  442.    * @param array $list 
  443.    * @param integer $start 
  444.    * @param integer $end 
  445.    * @returns array
  446.    * @access private
  447.    ***/
  448.   function listify($list$start$end{
  449.  
  450.     //Re-form a list, merge elements start->end into one quoted element
  451.     //Start and end are offsets...
  452.  
  453.     $l=$end-$start;
  454.  
  455.     $s=array_slice($list0$start);
  456.     $m=array_slice($list$start,$l);
  457.     $e=array_slice($list$end);
  458.   
  459.     //  array_push($s,"\"".join($m," ")."\"");
  460.     array_push($s,$m);
  461.   
  462.     return $this->array_concat($s,$e);
  463.   }
  464.  
  465.   /**
  466.    * Returns an array with prefixes=>namespace mappings
  467.    * @param array $list 
  468.    * @access private
  469.    * @returns array
  470.    ***/
  471.   function getPrefixes($list{
  472.  
  473.     $prefixes=array();
  474.     $ns=1;
  475.     $name=2;
  476.     foreach ($list as $l
  477.       if ($l=='@prefix'
  478.     //   while '@prefix' in list {
  479.       
  480.     $pos=current($list);
  481.     //pos = list.index('@prefix')
  482.     $r $this->getSpan($list$pos($pos+4))# processes the prefix tokens
  483.     $binding=$r[0];
  484.     $list=$r[1];
  485.     $prefixes[$binding[$ns]] substr($binding[$name],1,-1);
  486.     $this->parsedNamespaces[substr($binding[$name],1,-1)substr($binding[$ns],0,-1);
  487.       }
  488.     }
  489.  
  490.     if (count($prefixes)<1$listarray_slice($list,0);
  491.     
  492.     return array($prefixes$list);
  493.   }
  494.  
  495.   /**
  496.    * Callback function for replacing "a" elements with the right RDF uri.
  497.    * @param string $l 
  498.    * @access private
  499.    ***/
  500.   function replace_a_type(&$l,$p{
  501.     if ($l=='a'$l='<'.$this->RDF_NS.'type>';
  502.   }
  503.  
  504.   /**
  505.    * Callback function for replacing "=" elements with the right DAML+OIL uri.
  506.    * @param string $l 
  507.    * @access private
  508.    ***/
  509.   function replace_equal(&$l,$p{
  510.     if ($l=='='$l='<'.$this->OWL_NS.'sameAs>';
  511.   }
  512.  
  513.   /**
  514.    * Callback function for replacing "this" elements with the right RDF uri.
  515.    * @param string $l 
  516.    * @access private
  517.    ***/
  518.   function replace_this($l,$p{
  519.     if ($l=='this'$l='<urn:urn-n:this>';
  520.   }
  521.  
  522.   /**
  523.    * Applies stuff :)
  524.    * Expands namespace prefixes etc.
  525.    * @param array $prefixes 
  526.    * @param array $list 
  527.    * @returns $list
  528.    * @access private
  529.    ***/
  530.   function applyStuff($prefixes$list{
  531.  
  532.     array_walk($listarray($this'replace_a_type'));
  533.     array_walk($listarray($this'replace_equal'));
  534.     array_walk($listarray($this'replace_this'));
  535.  
  536.     for ($i=0;$i<count($list);$i++
  537.       //   for i in range(len(list)) {
  538. //      if (!strstr('<_"?.;,{}[]()',$list[$i]{0})) {
  539.  
  540.  
  541. // if a <> resource occours, change it to the parsed filename or local URI + timestamp
  542.  
  543.         if ($list[$i]=='<>'{
  544.             if (!isset($path)) 
  545.                 if (!isset($_SERVER['SERVER_ADDR'])) $_SERVER['SERVER_ADDR']='localhost';
  546.                 if (!isset($_SERVER['REQUEST_URI'])) $_SERVER['REQUEST_URI']='/rdfapi-php';
  547.                 $list[$i]='<http://'.$_SERVER['SERVER_ADDR'].$_SERVER['REQUEST_URI'].'#generate_timestamp_'.time().'>';
  548.                 
  549.           }else {$list[$i]='<'.$path.'>';};
  550.         };        
  551.  
  552.  
  553.         if ((!strstr('<_"?.;,{}[]()@',$list[$i]{0}))AND (substr($list[$i],0,3)!='^^<')) {
  554.       $_rexplode(":",$list[$i]);
  555.  
  556.  
  557.  
  558.  
  559.  
  560.     $ns=$_r[0].':';
  561.     $name=$_r[1];
  562.   
  563.     if (isset($prefixes[$ns])) $list[$i'<'.$prefixes[$ns].$name.'>';
  564.     else if (isset($prefixes[substr($ns,2)])) $list[$i'^^'.$prefixes[substr($ns,2)].$name.''
  565.   else {
  566.   #die('Prefix not declared:'.$ns);
  567.       $this->parseError=true;
  568.     trigger_error('Prefix not declared: '.$nsE_USER_ERROR);
  569.     break;
  570.     
  571.     
  572.   }
  573.   
  574.       else {       
  575.     if ($list[$i]{0== '"'{  // Congratulations - it's a literal!
  576.       if (substr($list[$i],0,3== '"""'{
  577.         if (substr($list[$i],-3,3== '"""'// A big literal...
  578.           $lit substr($list[$i],3,-3);         
  579.           //          print "++$lit++";
  580.           $lit=str_replace('\n''\\n',$lit);
  581.  
  582.           $lit=ereg_replace("[^\\]\"""\\\""$lit);
  583.  
  584.           $list[$i'"'.$lit.'"';
  585.         }
  586.         else die ('Incorrect string formatting: '.substr($list[$i],-3,3))}
  587.       else {
  588.         if (strstr($list[$i],"\n")) die('Newline in literal: '+$list[$i]);
  589.       }
  590.     }
  591.       }
  592.     
  593.       if (substr($list[$i],0,2)=='^^'{
  594.         if ($list[$i][2]!='<'){$list[$i]='^^<'.substr($list[$i],2).'>';};
  595.       };
  596.  
  597.     
  598.     }
  599.  
  600.  
  601.     return $list;
  602.   }
  603.  
  604.   /** 
  605.    * Returns an array of triples extracted from the list of n3 tokens
  606.    * @param array $list 
  607.    * @returns array
  608.    * @access private
  609.    ***/
  610.   function getStatements($list{
  611.  
  612.  
  613.     $statements array();
  614.  
  615.     while (in_array('.'$list)) {
  616.       //  for($i=0;$i<count($list); $i++) {
  617.       //    if ($list[$i]==".") {
  618.       //   while '.' in list {
  619.       $pos=array_search('.',$list);
  620.  
  621.       $r=$this->getSpan($list0$pos+1);    
  622.  
  623.       $statement=$r[0];
  624.       $list $r[1];
  625.  
  626.       array_pop($statement);
  627.       $statements[]=$statement;
  628.     }
  629.  
  630.     return $statements;
  631.   }
  632.   
  633.   /** 
  634.    * Gets a list of triples with same subject
  635.    * e.g. :Gunnar :firstname "Gunnar" ; :lastname "Grimnes.
  636.    * @param array $list 
  637.    * @returns array
  638.    * @acces private
  639.    ***/
  640.   function getPovs($list{
  641.     $povs array();
  642.     while (in_array(';'$list)) {
  643.       $r=$this->posns($list,';');
  644.       $pos=array_slice($r,0,2);
  645.       $r $this->getSpan($list$pos[0]$pos[1]);
  646.       $pov=$r[0];
  647.       $list=$r[1];
  648.  
  649.       // skip lone semicolons, e.g. "<a> <b> <c> ; ."
  650.       if (count($pov== 1continue;
  651.  
  652.       $povs[]=array_slice($pov,1);
  653.     }
  654.  
  655.     return array($list$povs);
  656.   }
  657.  
  658.   /** 
  659.    * Gets a list of triples with same predicate
  660.    * e.g. :Gunnar :likes "Cheese", "Wine".
  661.    * @access private
  662.    * @param array $list 
  663.    * @returns array
  664.    ***/
  665.   function getObjs($list{
  666.  
  667.  
  668.     $objs array();
  669.     while (in_array(",",$list)) {
  670.       $pos=array_search(",",$list);
  671.       //  for($i=0;$i<count($list); $i++) {
  672.       //    if ($list[$i]==",") {
  673.       //   while ',' in list {
  674.  
  675.  
  676.       $get_array_fields=2;
  677.       if (isset ($list[$pos+2])) 
  678.           if (@$list[$pos+2][0]=='@'$get_array_fields++;
  679.         if (@$list[$pos+2][0]=='^'$get_array_fields++;
  680.       };
  681.       if (isset ($list[$pos+3])) if (@$list[$pos+3][0]=='^'$get_array_fields++;};
  682.  
  683.  
  684.       $r=$this->getSpan($list$pos($pos+$get_array_fields));
  685.  
  686.       $obj=$r[0];
  687.       if (!isset($obj[2])) $obj[2]=' ';
  688.       if (!isset($obj[3])) $obj[3]=' ';
  689.       
  690.       $list=$r[1];
  691.  
  692.      
  693.       $objs[]=$obj;
  694.  
  695.  
  696.     }
  697.   
  698.     return array($list$objs);
  699.   }
  700.  
  701.   /**
  702.    * Does the real work, returns a list of subject, predicate, object triples.
  703.    * @param array $list 
  704.    * @returns array
  705.    * @access private
  706.    ***/
  707.   function statementize($list{
  708.  
  709.     if (count($list== && preg_match("/_".BNODE_PREFIX."[0-9]+_/",$list[0])) 
  710.     if ($this->debugprint "Ignored bNode exists statement$list\n";
  711.     return array()
  712.     }
  713.  
  714.     
  715.     
  716.     if (count($list== 3return array($list);
  717.     if (count($list3die("Error: statement too short!");
  718.  
  719.     //Get all ; 
  720.     $r=$this->getPovs($list);
  721.     $spo=$r[0];
  722.     $po=$r[1];
  723.     $all=array();
  724.  
  725.  
  726.  
  727.     //      (spo, po), all = getPovs(list), []
  728.     $subject $spo[0];
  729.     foreach ($po as $pop{
  730.       //  for pop in po {
  731.       $r=$this->getObjs($pop);
  732.  
  733.       $myPo=$r[0];
  734.       $obj=$r[1];
  735.       //myPo, obj = getObjs(pop)
  736.  
  737.       if (!isset($myPo[2])) $myPo[2]=' ';
  738.       if (!isset($myPo[3])) $myPo[3]=' ';
  739.  
  740.     
  741.       $predicate $myPo[0];
  742.       $all[]=array($subject,$predicate,$myPo[1],$myPo[2],$myPo[3]);
  743.       //    all.append([subject, predicate, myPo[1]])
  744.  
  745.        
  746.  
  747.       foreach ($obj as $o$all[]=array($subject,$predicate$o[1],$o[2],$o[3]);
  748.       //         for x in obj: all.append([subject, predicate, x])
  749.  
  750.     }
  751.  
  752.  
  753.  
  754.     $r $this->getObjs($spo);
  755.     $spo=$r[0];
  756.  
  757.     $objs=$r[1];
  758.  
  759.     //spo, objs = getObjs(spo)
  760.     $subject=$spo[0];
  761.     $predicate=$spo[1];
  762.  
  763.     
  764.     if(!isset($spo[3])) $spo[3]=' ';     
  765.     if(!isset($spo[4])) $spo[4]=' ';     
  766.       
  767.     $all[]=array($subject$predicate$spo[2],$spo[3],$spo[4]);
  768.  
  769.     foreach ($objs as $obj$all[]=array($subject$predicate$obj[1],$obj[2],$obj[3]);
  770.  
  771.     return $all;
  772.   }
  773.  
  774.   /**
  775.    * Makes lists of elements in list into a seperate array element.
  776.    * e.g. doLists(["a","b","[","c","]","d"], "[","]")=> ["a","b", ["c"], "d"]
  777.    * @param array $list 
  778.    * @param string $schar 
  779.    * @param string $echar 
  780.    * @returns array
  781.    * @access private
  782.    ***/
  783.   function doLists($list$schar$echar{
  784.  
  785.     while (in_array($schar$list)) {
  786.       //   while schar in list {
  787.       $ndict=array();
  788.       $nestingLevel=0;
  789.       $biggest=0;
  790.       for ($i=0;$i<count($list);$i++{
  791.     if ($list[$i== $schar{
  792.       $nestingLevel += 1;
  793.       if (!in_array($nestingLevelarray_keys($ndict))) {
  794.         $ndict[$nestingLevelarray(array($i));
  795.       else 
  796.         $ndict[$nestingLevel][]=array($i);
  797.       }
  798.     }
  799.     if ($list[$i== $echar{
  800.       if (!in_array($nestingLevelarray_keys($ndict))) {
  801.         $ndict[$nestingLevel]=array(array($i));
  802.       else 
  803.             $ndict[$nestingLevel][count($ndict[$nestingLevel])-1][]=$i;
  804.             $nestingLevel-= 1;
  805. # elif type(list[i]) == type([]) {
  806. #    list[i] = doLists(list[i], schar, echar)
  807.       }
  808.     }
  809.       }
  810.       foreach (array_keys($ndictas $key
  811.     if ($key $biggest)  $biggest $key;
  812.  
  813.       $tol $ndict[$biggest][0];
  814.       $list $this->listify($list$tol[0]($tol[1]+1));
  815.     }
  816.     return $list;
  817.   }
  818.  
  819.   /** 
  820.    * Apply doLists for all different types of list.
  821.    * @param array 
  822.    * @returns array
  823.    * @access private
  824.    ***/
  825.   function listStuff($list{
  826. # y, z = zip(['[', ']'], ['{', '}'], ['(', ')'])
  827. # return map(doLists, [list, list, list], y, z).pop()
  828.     $list $this->doLists($list'['']');
  829.     $list $this->doLists($list'{''}');
  830.     return $this->doLists($list'('')');
  831.   }
  832.  
  833.   /**
  834.    * Generates a new node id.
  835.    * @access private
  836.    * @returns string
  837.    ***/
  838.   function bnodeID({
  839.   
  840.     $this->bNode++;
  841.     return "_".BNODE_PREFIX.$this->bNode."_";
  842.   }
  843.  
  844.   /** 
  845.    * This makes bNodes out of variables like _:a etc.
  846.    * @access private
  847.    * @param array $list 
  848.    * @returns array
  849.    ***/
  850.   function fixAnon($list{
  851. //    $map=array();
  852.     for($i=0;$i<count($list);$i++{
  853.       $l=$list[$i];
  854.       if (substr($l,0,2)=="_:"{
  855.       if (!isset($this->bNodeMap[$l])) {
  856.       $a=$this->bnodeID();
  857.       $this->bNodeMap[$l]=$a;
  858.     else $a=$this->bNodeMap[$l];
  859.     $list[$i]=$a;
  860.       }
  861.     }
  862.     return $list;
  863.   }
  864.  
  865.   /**
  866.    * This makes [ ] lists into bnodes.
  867.    * @access private
  868.    * @param array $list 
  869.    * @return array 
  870.    ***/
  871.   function expandLists($list{
  872.  
  873.     for($i=0;$i<count($list);$i++{
  874.       if (is_array($list[$i])) {
  875.     if $list[$i][0]=='[' {
  876.       $bnode=$this->bnodeID();
  877.       $prop=$list[$i];
  878.       $list[$i]=$bnode;
  879.       $list[]=$bnode;
  880.       $list=$this->array_concat($listarray_slice($prop,1,-1));
  881.       $list[]='.';
  882.     }elseif($list[$i][0]=='('{
  883.  
  884.         $rdfNil '<'RDF_NAMESPACE_URI RDF_NIL .'>';
  885.         $rdfFirst '<'RDF_NAMESPACE_URI RDF_FIRST .'>';
  886.         $rdfRest '<'RDF_NAMESPACE_URI RDF_REST .'>';
  887.  
  888.         // local copy of list without "(" and ")"
  889.         $t_list array_slice($list[$i]1-1);
  890.  
  891.         //prepare bnodes
  892.         $fromBnode $this->bnodeID();
  893.         $toBnode $this->bnodeID();
  894.  
  895.         //link first bnode into graph
  896.         $list[$i$fromBnode;
  897.  
  898.         $count count($t_list);
  899.  
  900.         //loop through list, convert to RDF linked list
  901.         for ($idx 0$idx $count$idx++){
  902.  
  903.             // set rdf:first
  904.             $list[$fromBnode;
  905.             $list[$rdfFirst;
  906.             $list[$t_list[$idx];
  907.             $list['.';
  908.  
  909.             // set rdf:rest (nil or next bnode)
  910.             if ($idx == $count 1{
  911.                 $list[$fromBnode;
  912.                 $list[$rdfRest;
  913.                 $list[$rdfNil;
  914.                 $list['.';
  915.             }
  916.             else {
  917.                 $list[$fromBnode;
  918.                 $list[$rdfRest;
  919.                 $list[$toBnode;
  920.                 $list['.';
  921.  
  922.                 $fromBnode $toBnode;
  923.                 $toBnode $this->bnodeID();
  924.             }
  925.         }
  926.     }
  927.     else {
  928.         die('Only [ ] and () lists are supported!');
  929.     }
  930.     }
  931.  
  932.     
  933.     }
  934.     return $list;
  935.   }
  936.  
  937.   /** 
  938.    * Main work-horse function. This converts a N3 string to a list of statements
  939.    * @param string $s 
  940.    * @returns array
  941.    * @access private
  942.    ***/
  943.   function n3tolist($s{
  944.  
  945.     //   """Convert an N3 string into a list of triples as strings."""
  946.     $result array();
  947.  
  948.    $t $this->filterWs($this->toke($s))# tokenize the stream, and filter whitespace tokens
  949.  
  950.     if ($this->debug{
  951.       print "Filter WS:\n";
  952.       var_dump($t);
  953.     }
  954.     $r=$this->getPrefixes($t)# get the prefix directives, and add to a dict
  955.     $prefixes=$r[0];
  956.     $t=$r[1];
  957.     if ($this->debug{
  958.       print "Prefixes:\n";
  959.       var_dump($prefixes);
  960.       print "***\n";
  961.       var_dump($t);
  962.     }
  963.     $t=$this->applyStuff($prefixes$t);#apply prefixes, keywords, and string formatting 
  964.     if ($this->debug{
  965.       print "Stuff applied:\n";
  966.       var_dump($t);
  967.     }
  968.  
  969.     $t=$this->fixAnon($t)# fix _:a anons
  970.     if ($this->debug{
  971.       print "Fix anon:\n";
  972.       var_dump($t);
  973.     }
  974.     
  975.     $t $this->listStuff($t)# apply list stuff: todo
  976.     if ($this->debug{
  977.       print "Lists done:\n";
  978.       var_dump($t);
  979.     }
  980.     $t=$this->expandLists($t);
  981.     if ($this->debug{
  982.       print "Lists applied:\n";
  983.       var_dump($t);
  984.     }
  985.     $t $this->getStatements($t)# get all of the "statements" from the stream
  986.  
  987.     foreach ($t as $stat{
  988.       $stats=$this->statementize($stat);
  989.  
  990.       foreach ($stats as $y{
  991.     $result[]=$y;
  992.       }
  993.     }
  994.     //   for x in [statementize(stat) for stat in t] {
  995.     //      for y in x: result.append(y)
  996.     return $result;
  997.   }
  998.  
  999.   /** 
  1000.    * Constructs a RAP RDFNode from URI/Literal/Bnode
  1001.    * @access private
  1002.    * @param string $s 
  1003.    * @returns object RDFNode
  1004.    ***/
  1005.   function toRDFNode($s,$state{
  1006.     $ins=substr($s,1,-1);
  1007.     if ($s{0}=="\""{
  1008.       $lang=NULL;
  1009.     
  1010.  
  1011.  
  1012.       if (count($state)>3{           
  1013.  
  1014.  
  1015.         for ($i 3$i count($state)$i++){
  1016.           if ($state[$i][0]=='@')$lang=substr($state[3],1);
  1017.           if (substr($state[$i],0,2)=='^^'){
  1018.             
  1019.             $dtype=substr($state[$i],2);
  1020.             if ($dtype[0]=='<'$dtypesubstr($dtype,1,-1);
  1021.             
  1022.           };
  1023.           
  1024.         };
  1025.       };
  1026.       
  1027.     
  1028.      if(UNIC_RDF){
  1029.           $ins=$this->str2unicode_nfc($ins);
  1030.       }
  1031.       $new_Literal=new Literal($ins,$lang);
  1032.       if (isset($dtype)) $new_Literal->setDatatype($dtype);     
  1033.       return  $new_Literal;        
  1034.     };
  1035.  
  1036.     if (strstr($s,'_'.BNODE_PREFIX)) 
  1037.         if (($this->FixBnodesOR (!array_search($s,$this->bNodeMap))) {
  1038.             return new BlankNode($ins);
  1039.         else {return new BlankNode(trim(substr(array_search($s,$this->bNodeMap),2)));
  1040.         };
  1041.     }
  1042.     
  1043.     return new Resource($ins)
  1044.   }
  1045.  
  1046.  
  1047.   
  1048.   
  1049. //end: N3Parser
  1050.  
  1051. ?>

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