source: Dev/branches/rest-dojo-ui/jQueryUI/server/rdfapi/syntax/N3Parser.php @ 312

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