source: pmb4.2/trunk/fuentes/pmb/classes/rdf/arc2/parsers/ARC2_TurtleParser.php @ 815

Last change on this file since 815 was 815, checked in by jrpelegrina, 4 years ago

Initial release of pmb 4.2

  • Property svn:executable set to *
File size: 26.7 KB
Line 
1<?php
2/**
3 * ARC2 SPARQL-enhanced Turtle Parser
4 *
5 * @author Benjamin Nowack
6 * @license <http://arc.semsol.org/license>
7 * @homepage <http://arc.semsol.org/>
8 * @package ARC2
9 * @version 2010-11-16
10*/
11
12ARC2::inc('RDFParser');
13
14class ARC2_TurtleParser extends ARC2_RDFParser {
15
16  function __construct($a, &$caller) {
17    parent::__construct($a, $caller);
18  }
19 
20  function __init() {/* reader */
21    parent::__init();
22    $this->state = 0;
23    $this->xml = 'http://www.w3.org/XML/1998/namespace';
24    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
25    $this->xsd = 'http://www.w3.org/2001/XMLSchema#';
26    $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf', $this->xsd => 'xsd');
27    $this->unparsed_code = '';
28    $this->max_parsing_loops = $this->v('turtle_max_parsing_loops', 500, $this->a);
29  }
30 
31  /*  */
32 
33  function x($re, $v, $options = 'si') {
34    $v = preg_replace('/^[\xA0\xC2]+/', ' ', $v);
35    while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $v, $m)) {/* comment removal */
36      $v = $m[2];
37    }
38    return ARC2::x($re, $v, $options);
39    //$this->unparsed_code = ($sub_r && count($sub_r)) ? $sub_r[count($sub_r) - 1] : '';
40  }
41
42  function createBnodeID(){
43    $this->bnode_id++;
44    return '_:' . $this->bnode_prefix . $this->bnode_id;
45  }
46
47  /*  */
48 
49  function addT($t) {
50    if ($this->skip_dupes) {
51      $h = md5(serialize($t));
52      if (!isset($this->added_triples[$h])) {
53        $this->triples[$this->t_count] = $t;
54        $this->t_count++;
55        $this->added_triples[$h] = true;
56      }
57    }
58    else {
59      $this->triples[$this->t_count] = $t;
60      $this->t_count++;
61    }
62  }
63
64  /*  */
65
66  function getTriples() {
67    return $this->v('triples', array());
68  }
69 
70  function countTriples() {
71    return $this->t_count;
72  }
73 
74  /*  */
75 
76  function getUnparsedCode() {
77    return $this->v('unparsed_code', '');
78  }
79 
80  /*  */
81 
82  function setDefaultPrefixes() {
83    $this->prefixes = array(
84      'rdf:' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
85      'rdfs:' => 'http://www.w3.org/2000/01/rdf-schema#',
86      'owl:' => 'http://www.w3.org/2002/07/owl#',
87      'xsd:' => 'http://www.w3.org/2001/XMLSchema#',
88    );
89    if ($ns = $this->v('ns', array(), $this->a)) {
90      foreach ($ns as $p => $u) $this->prefixes[$p . ':'] = $u;
91    }
92  }
93 
94
95  function parse($path, $data = '', $iso_fallback = false) {
96    $this->setDefaultPrefixes();
97    /* reader */
98    if (!$this->v('reader')) {
99      ARC2::inc('Reader');
100      $this->reader = new ARC2_Reader($this->a, $this);
101    }
102    $this->reader->setAcceptHeader('Accept: application/x-turtle; q=0.9, */*; q=0.1');
103    $this->reader->activate($path, $data);
104    $this->base = $this->v1('base', $this->reader->base, $this->a);
105    $this->r = array('vars' => array());
106    /* parse */
107    $buffer = '';
108    $more_triples = array();
109    $sub_v = '';
110    $sub_v2 = '';
111    $loops = 0;
112    $prologue_done = 0;
113    while ($d = $this->reader->readStream(0, 8192)) {
114      $buffer .= $d;
115      $sub_v = $buffer;
116      do {
117        $proceed = 0;
118        if (!$prologue_done) {
119          $proceed = 1;
120          if ((list($sub_r, $sub_v) = $this->xPrologue($sub_v)) && $sub_r) {
121            $loops = 0;
122            $sub_v .= $this->reader->readStream(0, 128);
123            /* we might have missed the final DOT in the previous prologue loop */
124            if ($sub_r = $this->x('\.', $sub_v)) $sub_v = $sub_r[1];
125            if ($this->x("\@?(base|prefix)", $sub_v)) {/* more prologue to come, use outer loop */
126              $proceed = 0;
127            }
128          }
129          else {
130            $prologue_done = 1;
131          }
132        }
133        if ($prologue_done && (list($sub_r, $sub_v, $more_triples, $sub_v2) = $this->xTriplesBlock($sub_v)) && is_array($sub_r)) {
134          $proceed = 1;
135          $loops = 0;
136          foreach ($sub_r as $t) {
137            $this->addT($t);
138          }
139        }
140      } while ($proceed);
141      $loops++;
142      $buffer = $sub_v;
143      if ($loops > $this->max_parsing_loops) {/* most probably a parser or code bug, might also be a huge object value, though */
144        $this->addError('too many loops: ' . $loops . '. Could not parse "' . substr($buffer, 0, 200) . '..."');
145        break;
146      }
147    }
148    foreach ($more_triples as $t) {
149      $this->addT($t);
150    }
151    $sub_v = count($more_triples) ? $sub_v2 : $sub_v;
152    $buffer = $sub_v;
153    $this->unparsed_code = $buffer;
154    $this->reader->closeStream();
155    unset($this->reader);
156    /* remove trailing comments */
157    while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $this->unparsed_code, $m)) $this->unparsed_code = $m[2];
158    if ($this->unparsed_code && !$this->getErrors()) {
159      $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
160      if (trim($rest)) $this->addError('Could not parse "' . $rest . '"');
161    }
162    return $this->done();
163  }
164
165  function xPrologue($v) {
166    $r = 0;
167    if (!$this->t_count) {
168      if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
169        $this->base = $sub_r;
170        $r = 1;
171      }
172      while ((list($sub_r, $v) = $this->xPrefixDecl($v)) && $sub_r) {
173        $this->prefixes[$sub_r['prefix']] = $sub_r['uri'];
174        $r = 1;
175      }
176    }
177    return array($r, $v);
178  }
179 
180  /* 3 */
181
182  function xBaseDecl($v) {
183    if ($r = $this->x("\@?base\s+", $v)) {
184      if ((list($r, $sub_v) = $this->xIRI_REF($r[1])) && $r) {
185        if ($sub_r = $this->x('\.', $sub_v)) {
186          $sub_v = $sub_r[1];
187        }
188        return array($r, $sub_v);
189      }
190    }
191    return array(0, $v);
192  }
193 
194  /* 4 */
195 
196  function xPrefixDecl($v) {
197    if ($r = $this->x("\@?prefix\s+", $v)) {
198      if ((list($r, $sub_v) = $this->xPNAME_NS($r[1])) && $r) {
199        $prefix = $r;
200        if((list($r, $sub_v) = $this->xIRI_REF($sub_v)) && $r) {
201          $uri = $this->calcURI($r, $this->base);
202          if ($sub_r = $this->x('\.', $sub_v)) {
203            $sub_v = $sub_r[1];
204          }
205          return array(array('prefix' => $prefix, 'uri_ref' => $r, 'uri' => $uri), $sub_v);
206        }
207      }
208    }
209    return array(0, $v);
210  }
211
212  /* 21.., 32.. */
213 
214  function xTriplesBlock($v) {
215    $pre_r = array();
216    $r = array();
217    $state = 1;
218    $sub_v = $v;
219    $buffer = $sub_v;
220    do {
221      $proceed = 0;
222      if ($state == 1) {/* expecting subject */
223        $t = array('type' => 'triple', 's' => '', 'p' => '', 'o' => '', 's_type' => '', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => '');
224        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
225          $t['s'] = $sub_r['value'];
226          $t['s_type'] = $sub_r['type'];
227          $state = 2;
228          $proceed = 1;
229          if ($sub_r = $this->x('(\}|\.)', $sub_v)) {
230            if ($t['s_type'] == 'placeholder') {
231              $state = 4;
232            }
233            else {
234              $this->addError('"' . $sub_r[1]. '" after subject found.');
235            }
236          }
237        }
238        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
239          $t['s'] = $sub_r['id'];
240          $t['s_type'] = $sub_r['type'];
241          $pre_r = array_merge($pre_r, $sub_r['triples']);
242          $state = 2;
243          $proceed = 1;
244          if ($sub_r = $this->x('\.', $sub_v)) {
245            $this->addError('DOT after subject found.');
246          }
247        }
248        elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
249          $t['s'] = $sub_r['id'];
250          $t['s_type'] = $sub_r['type'];
251          $pre_r = array_merge($pre_r, $sub_r['triples']);
252          $state = 2;
253          $proceed = 1;
254        }
255        elseif ($sub_r = $this->x('\.', $sub_v)) {
256          $this->addError('Subject expected, DOT found.' . $sub_v);
257        }
258      }
259      if ($state == 2) {/* expecting predicate */
260        if ($sub_r = $this->x('a\s+', $sub_v)) {
261          $sub_v = $sub_r[1];
262          $t['p'] = $this->rdf . 'type';
263          $t['p_type'] = 'uri';
264          $state = 3;
265          $proceed = 1;
266        }
267        elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
268          if ($sub_r['type'] == 'bnode') {
269            $this->addError('Blank node used as triple predicate');
270          }
271          $t['p'] = $sub_r['value'];
272          $t['p_type'] = $sub_r['type'];
273          $state = 3;
274          $proceed = 1;
275        }
276        elseif ($sub_r = $this->x('\.', $sub_v)) {
277          $state = 4;         
278        }
279        elseif ($sub_r = $this->x('\}', $sub_v)) {
280          $buffer = $sub_v;
281          $r = array_merge($r, $pre_r);
282          $pre_r = array();
283          $proceed = 0;
284        }
285      }
286      if ($state == 3) {/* expecting object */
287        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
288          $t['o'] = $sub_r['value'];
289          $t['o_type'] = $sub_r['type'];
290          $t['o_lang'] = $this->v('lang', '', $sub_r);
291          $t['o_datatype'] = $this->v('datatype', '', $sub_r);
292          $pre_r[] = $t;
293          $state = 4;
294          $proceed = 1;
295        }
296        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
297          $t['o'] = $sub_r['id'];
298          $t['o_type'] = $sub_r['type'];
299          $pre_r = array_merge($pre_r, array($t), $sub_r['triples']);
300          $state = 4;
301          $proceed = 1;
302        }
303        elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
304          $t['o'] = $sub_r['id'];
305          $t['o_type'] = $sub_r['type'];
306          $pre_r = array_merge($pre_r, array($t), $sub_r['triples']);
307          $state = 4;
308          $proceed = 1;
309        }
310      }
311      if ($state == 4) {/* expecting . or ; or , or } */
312        if ($sub_r = $this->x('\.', $sub_v)) {
313          $sub_v = $sub_r[1];
314          $buffer = $sub_v;
315          $r = array_merge($r, $pre_r);
316          $pre_r = array();
317          $state = 1;
318          $proceed = 1;
319        }
320        elseif ($sub_r = $this->x('\;', $sub_v)) {
321          $sub_v = $sub_r[1];
322          $state = 2;
323          $proceed = 1;
324        }
325        elseif ($sub_r = $this->x('\,', $sub_v)) {
326          $sub_v = $sub_r[1];
327          $state = 3;
328          $proceed = 1;
329          if ($sub_r = $this->x('\}', $sub_v)) {
330            $this->addError('Object expected, } found.');
331          }
332        }
333        if ($sub_r = $this->x('(\}|\{|OPTIONAL|FILTER|GRAPH)', $sub_v)) {
334          $buffer = $sub_v;
335          $r = array_merge($r, $pre_r);
336          $pre_r = array();
337          $proceed = 0;
338        }
339      }
340    } while ($proceed);
341    return count($r) ? array($r, $buffer, $pre_r, $sub_v) : array(0, $buffer, $pre_r, $sub_v);
342  }
343 
344  /* 39.. */
345 
346  function xBlankNodePropertyList($v) {
347    if ($sub_r = $this->x('\[', $v)) {
348      $sub_v = $sub_r[1];
349      $s = $this->createBnodeID();
350      $r = array('id' => $s, 'type' => 'bnode', 'triples' => array());
351      $t = array('type' => 'triple', 's' => $s, 'p' => '', 'o' => '', 's_type' => 'bnode', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => '');
352      $state = 2;
353      $closed = 0;
354      do {
355        $proceed = 0;
356        if ($state == 2) {/* expecting predicate */
357          if ($sub_r = $this->x('a\s+', $sub_v)) {
358            $sub_v = $sub_r[1];
359            $t['p'] = $this->rdf . 'type';
360            $t['p_type'] = 'uri';
361            $state = 3;
362            $proceed = 1;
363          }
364          elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
365            $t['p'] = $sub_r['value'];
366            $t['p_type'] = $sub_r['type'];
367            $state = 3;
368            $proceed = 1;
369          }
370        }
371        if ($state == 3) {/* expecting object */
372          if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
373            $t['o'] = $sub_r['value'];
374            $t['o_type'] = $sub_r['type'];
375            $t['o_lang'] = $this->v('lang', '', $sub_r);
376            $t['o_datatype'] = $this->v('datatype', '', $sub_r);
377            $r['triples'][] = $t;
378            $state = 4;
379            $proceed = 1;
380          }
381          elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
382            $t['o'] = $sub_r['id'];
383            $t['o_type'] = $sub_r['type'];
384            $r['triples'] = array_merge($r['triples'], array($t), $sub_r['triples']);
385            $state = 4;
386            $proceed = 1;
387          }
388          elseif((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
389            $t['o'] = $sub_r['id'];
390            $t['o_type'] = $sub_r['type'];
391            $r['triples'] = array_merge($r['triples'], array($t), $sub_r['triples']);
392            $state = 4;
393            $proceed = 1;
394          }
395        }
396        if ($state == 4) {/* expecting . or ; or , or ] */
397          if ($sub_r = $this->x('\.', $sub_v)) {
398            $sub_v = $sub_r[1];
399            $state = 1;
400            $proceed = 1;
401          }
402          if ($sub_r = $this->x('\;', $sub_v)) {
403            $sub_v = $sub_r[1];
404            $state = 2;
405            $proceed = 1;
406          }
407          if ($sub_r = $this->x('\,', $sub_v)) {
408            $sub_v = $sub_r[1];
409            $state = 3;
410            $proceed = 1;
411          }
412          if ($sub_r = $this->x('\]', $sub_v)) {
413            $sub_v = $sub_r[1];
414            $proceed = 0;
415            $closed = 1;
416          }
417        }
418      } while ($proceed);
419      if ($closed) {
420        return array($r, $sub_v);
421      }
422      return array(0, $v);
423    }
424    return array(0, $v);
425  }
426 
427  /* 40.. */
428 
429  function xCollection($v) {
430    if ($sub_r = $this->x('\(', $v)) {
431      $sub_v = $sub_r[1];
432      $s = $this->createBnodeID();
433      $r = array('id' => $s, 'type' => 'bnode', 'triples' => array());
434      $closed = 0;
435      do {
436        $proceed = 0;
437        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
438          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['value'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => $this->v('lang', '', $sub_r), 'o_datatype' => $this->v('datatype', '', $sub_r));
439          $proceed = 1;
440        }
441        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
442          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => '');
443          $r['triples'] = array_merge($r['triples'], $sub_r['triples']);
444          $proceed = 1;
445        }
446        elseif((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
447          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => '');
448          $r['triples'] = array_merge($r['triples'], $sub_r['triples']);
449          $proceed = 1;
450        }
451        if ($proceed) {
452          if ($sub_r = $this->x('\)', $sub_v)) {
453            $sub_v = $sub_r[1];
454            $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'rest', 'o' => $this->rdf . 'nil', 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'uri', 'o_lang' => '', 'o_datatype' => '');
455            $closed = 1;
456            $proceed = 0;
457          }
458          else {
459            $next_s = $this->createBnodeID();
460            $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'rest', 'o' => $next_s, 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'bnode', 'o_lang' => '', 'o_datatype' => '');
461            $s = $next_s;
462          }
463        }
464      } while ($proceed);
465      if ($closed) {
466        return array($r, $sub_v);
467      }
468    }
469    return array (0, $v);
470  }
471 
472  /* 42 */
473 
474  function xVarOrTerm($v) {
475    if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
476      return array($sub_r, $sub_v);
477    }
478    elseif ((list($sub_r, $sub_v) = $this->xGraphTerm($v)) && $sub_r) {
479      return array($sub_r, $sub_v);
480    }
481    return array(0, $v);
482  }
483 
484  /* 44, 74.., 75.. */
485 
486  function xVar($v) {
487    if ($r = $this->x('(\?|\$)([^\s]+)', $v)) {
488      if ((list($sub_r, $sub_v) = $this->xVARNAME($r[2])) && $sub_r) {
489        if (!in_array($sub_r, $this->r['vars'])) {
490          $this->r['vars'][] = $sub_r;
491        }
492        return array(array('value' => $sub_r, 'type' => 'var'), $sub_v . $r[3]);
493      }
494    }
495    return array(0, $v);
496  }
497
498  /* 45 */
499 
500  function xGraphTerm($v) {
501    foreach (array(
502      'IRIref' => 'uri', 
503      'RDFLiteral' => 'literal', 
504      'NumericLiteral' => 'literal', 
505      'BooleanLiteral' => 'literal', 
506      'BlankNode' => 'bnode', 
507      'NIL' => 'uri',
508      'Placeholder' => 'placeholder'
509    ) as $term => $type) {
510      $m = 'x' . $term;
511      if ((list($sub_r, $sub_v) = $this->$m($v)) && $sub_r) {
512        if (!is_array($sub_r)) {
513          $sub_r = array('value' => $sub_r);
514        }
515        $sub_r['type'] = $this->v1('type', $type, $sub_r);
516        return array($sub_r, $sub_v);
517      }
518    }
519    return array(0, $v);
520  }
521
522  /* 60 */
523 
524  function xRDFLiteral($v) {
525    if ((list($sub_r, $sub_v) = $this->xString($v)) && $sub_r) {
526      $sub_r['value'] = $this->unescapeNtripleUTF($sub_r['value']);
527      $r = $sub_r;
528      if ((list($sub_r, $sub_v) = $this->xLANGTAG($sub_v)) && $sub_r) {
529        $r['lang'] = $sub_r;
530      }
531      elseif (!$this->x('\s', $sub_v) && ($sub_r = $this->x('\^\^', $sub_v)) && (list($sub_r, $sub_v) = $this->xIRIref($sub_r[1])) && $sub_r[1]) {
532        $r['datatype'] = $sub_r;
533      }
534      return array($r, $sub_v);
535    }
536    return array(0, $v);
537  }
538
539  /* 61.., 62.., 63.., 64.. */ 
540 
541  function xNumericLiteral($v) {
542    $sub_r = $this->x('(\-|\+)?', $v);
543    $prefix = $sub_r[1];
544    $sub_v = $sub_r[2];
545    foreach (array('DOUBLE' => 'double', 'DECIMAL' => 'decimal', 'INTEGER' => 'integer') as $type => $xsd) {
546      $m = 'x' . $type;
547      if ((list($sub_r, $sub_v) = $this->$m($sub_v)) && ($sub_r !== false)) {
548        $r = array('value' => $prefix . $sub_r, 'type' => 'literal', 'datatype' => $this->xsd . $xsd);
549        return array($r, $sub_v);
550      }
551    }
552    return array(0, $v);
553  }
554 
555  /* 65.. */
556 
557  function xBooleanLiteral($v) {
558    if ($r = $this->x('(true|false)', $v)) {
559      return array($r[1], $r[2]);
560    }
561    return array(0, $v);
562  }
563
564  /* 66.., 87.., 88.., 89.., 90.., 91.. */
565 
566  function xString($v) {/* largely simplified, may need some tweaks in following revisions */
567    $sub_v = $v;
568    if (!preg_match('/^\s*([\']{3}|\'|[\"]{3}|\")(.*)$/s', $sub_v, $m)) return array(0, $v);
569    $delim = $m[1];
570    $rest = $m[2];
571    $sub_types = array("'''" => 'literal_long1', '"""' => 'literal_long2', "'" => 'literal1', '"' => 'literal2');
572    $sub_type = $sub_types[$delim];
573    $pos = 0;
574    $r = false;
575    do {
576      $proceed = 0;
577      $delim_pos = strpos($rest, $delim, $pos);
578      if ($delim_pos === false) break;
579      $new_rest = substr($rest, $delim_pos + strlen($delim));
580      $r = substr($rest, 0, $delim_pos);
581      if (!preg_match('/([\x5c]+)$/s', $r, $m) || !(strlen($m[1]) % 2)) {
582        $rest = $new_rest;
583      }
584      else {
585        $r = false;
586        $pos = $delim_pos + 1;
587        $proceed = 1;
588      }
589    } while ($proceed);
590    if ($r !== false) {
591      return array(array('value' => $this->toUTF8($r) , 'type' => 'literal', 'sub_type' => $sub_type), $rest);
592    }
593    return array(0, $v);
594  }
595 
596  /* 67 */
597 
598  function xIRIref($v) {
599    if ((list($r, $v) = $this->xIRI_REF($v)) && $r) {
600      return array($this->calcURI($r, $this->base), $v);
601    }
602    elseif ((list($r, $v) = $this->xPrefixedName($v)) && $r) {
603      return array($r, $v);
604    }
605    return array(0, $v);
606  }
607 
608  /* 68 */
609 
610  function xPrefixedName($v) {
611    if ((list($r, $v) = $this->xPNAME_LN($v)) && $r) {
612      return array($r, $v);
613    }
614    elseif ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
615      return isset($this->prefixes[$r]) ? array($this->prefixes[$r], $sub_v) : array(0, $v);
616    }
617    return array(0, $v);
618  }
619 
620  /* 69.., 73.., 93, 94..  */
621 
622  function xBlankNode($v) {
623    if (($r = $this->x('\_\:', $v)) && (list($r, $sub_v) = $this->xPN_LOCAL($r[1])) && $r) {
624      return array(array('type' => 'bnode', 'value' => '_:' . $r), $sub_v);
625    }
626    if ($r = $this->x('\[[\x20\x9\xd\xa]*\]', $v)) {
627      return array(array('type' => 'bnode', 'value' => $this->createBnodeID()), $r[1]);
628    }
629    return array(0, $v);
630  }
631
632  /* 70.. @@sync with SPARQLParser */
633 
634  function xIRI_REF($v) {
635    //if ($r = $this->x('\<([^\<\>\"\{\}\|\^\'[:space:]]*)\>', $v)) {
636    if (($r = $this->x('\<(\$\{[^\>]*\})\>', $v)) && ($sub_r = $this->xPlaceholder($r[1]))) {
637      return array($r[1], $r[2]);
638    }
639    elseif ($r = $this->x('\<\>', $v)) {
640      return array(true, $r[1]);
641    }
642    elseif ($r = $this->x('\<([^\s][^\<\>]*)\>', $v)) {
643      return array($r[1] ? $r[1] : true, $r[2]);
644    }
645    return array(0, $v);
646  }
647 
648  /* 71 */
649 
650  function xPNAME_NS($v) {
651    list($r, $sub_v) = $this->xPN_PREFIX($v);
652    $prefix = $r ? $r : '';
653    return ($r = $this->x("\:", $sub_v)) ? array($prefix . ':', $r[1]) : array(0, $v);
654  }
655
656  /* 72 */
657 
658  function xPNAME_LN($v) {
659    if ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
660      if (!$this->x('\s', $sub_v) && (list($sub_r, $sub_v) = $this->xPN_LOCAL($sub_v)) && $sub_r) {
661        if (!isset($this->prefixes[$r])) {
662          return array(0, $v);
663        }
664        return array($this->prefixes[$r] . $sub_r, $sub_v);
665      }
666    }
667    return array(0, $v);
668  }
669 
670  /* 76 */
671 
672  function xLANGTAG($v) {
673    if (!$this->x('\s', $v) && ($r = $this->x('\@([a-z]+(\-[a-z0-9]+)*)', $v))) {
674      return array($r[1], $r[3]);
675    }
676    return array(0, $v);
677  }
678 
679  /* 77.. */
680 
681  function xINTEGER($v) {
682    if ($r = $this->x('([0-9]+)', $v)) {
683      return array($r[1], $r[2]);
684    }
685    return array(false, $v);
686  }
687
688  /* 78.. */
689
690  function xDECIMAL($v) {
691    if ($r = $this->x('([0-9]+\.[0-9]*)', $v)) {
692      return array($r[1], $r[2]);
693    }
694    if ($r = $this->x('(\.[0-9]+)', $v)) {
695      return array($r[1], $r[2]);
696    }
697    return array(false, $v);
698  }
699
700  /* 79.., 86.. */
701
702  function xDOUBLE($v) {
703    if ($r = $this->x('([0-9]+\.[0-9]*E[\+\-]?[0-9]+)', $v)) {
704      return array($r[1], $r[2]);
705    }
706    if ($r = $this->x('(\.[0-9]+E[\+\-]?[0-9]+)', $v)) {
707      return array($r[1], $r[2]);
708    }
709    if ($r = $this->x('([0-9]+E[\+\-]?[0-9]+)', $v)) {
710      return array($r[1], $r[2]);
711    }
712    return array(false, $v);
713  }
714 
715  /* 92 */
716 
717  function xNIL($v) {
718    if ($r = $this->x('\([\x20\x9\xd\xa]*\)', $v)) {
719      return array(array('type' => 'uri', 'value' => $this->rdf . 'nil'), $r[1]);
720    }
721    return array(0, $v);
722  }
723
724  /* 95.. */
725 
726  function xPN_CHARS_BASE($v) {
727    if ($r = $this->x("([a-z]+|\\\u[0-9a-f]{1,4})", $v)) {
728      return array($r[1], $r[2]);
729    }
730    return array(0, $v);
731  }
732
733  /* 96 */
734 
735  function xPN_CHARS_U($v) {
736    if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
737      return array($r, $sub_v);
738    }
739    elseif ($r = $this->x("(_)", $v)) {
740      return array($r[1], $r[2]);
741    }
742    return array(0, $v);
743  }
744
745  /* 97.. */
746 
747  function xVARNAME($v) {
748    $r = '';
749    do {
750      $proceed = 0;
751      if ($sub_r = $this->x('([0-9]+)', $v)) {
752        $r .= $sub_r[1];
753        $v = $sub_r[2];
754        $proceed = 1;
755      }
756      elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($v)) && $sub_r) {
757        $r .= $sub_r;
758        $v = $sub_v;
759        $proceed = 1;
760      }
761      elseif ($r && ($sub_r = $this->x('([\xb7\x300-\x36f]+)', $v))) {
762        $r .= $sub_r[1];
763        $v = $sub_r[2];
764        $proceed = 1;
765      }
766    } while ($proceed);
767    return array($r, $v);
768  }
769
770  /* 98.. */
771 
772  function xPN_CHARS($v) {
773    if ((list($r, $sub_v) = $this->xPN_CHARS_U($v)) && $r) {
774      return array($r, $sub_v);
775    }
776    elseif ($r = $this->x('([\-0-9\xb7\x300-\x36f])', $v)) {
777      return array($r[1], $r[2]);
778    }
779    return array(false, $v);
780  }
781
782  /* 99 */
783 
784  function xPN_PREFIX($v) {
785    if ($sub_r = $this->x("([^\s\:\(\)\{\}\;\,]+)", $v, 's')) {/* accelerator */
786      return array($sub_r[1], $sub_r[2]);/* @@testing */
787    }
788    if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
789      do {
790        $proceed = 0;
791        list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
792        if ($sub_r !== false) {
793          $r .= $sub_r;
794          $proceed = 1;
795        }
796        elseif ($sub_r = $this->x("\.", $sub_v)) {
797          $r .= '.';
798          $sub_v = $sub_r[1];
799          $proceed = 1;
800        }
801      } while ($proceed);
802      list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
803      $r .= $sub_r ? $sub_r : '';
804    }
805    return array($r, $sub_v);
806  }
807 
808  /* 100 */
809 
810  function xPN_LOCAL($v) {
811    if (($sub_r = $this->x("([^\s\(\)\{\}\[\]\;\,\.]+)", $v, 's')) && !preg_match('/^\./', $sub_r[2])) {/* accelerator */
812      return array($sub_r[1], $sub_r[2]);/* @@testing */
813    }
814    $r = '';
815    $sub_v = $v;
816    do {
817      $proceed = 0;
818      if ($this->x('\s', $sub_v)) {
819        return array($r, $sub_v);
820      }
821      if ($sub_r = $this->x('([0-9])', $sub_v)) {
822        $r .= $sub_r[1];
823        $sub_v = $sub_r[2];
824        $proceed = 1;
825      }
826      elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($sub_v)) && $sub_r) {
827        $r .= $sub_r;
828        $proceed = 1;
829      }
830      elseif ($r) {
831        if (($sub_r = $this->x('(\.)', $sub_v)) && !preg_match('/^[\s\}]/s', $sub_r[2])) {
832          $r .= $sub_r[1];
833          $sub_v = $sub_r[2];
834        }
835        if ((list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v)) && $sub_r) {
836          $r .= $sub_r;
837          $proceed = 1;
838        }
839      }
840    } while ($proceed);
841    return array($r, $sub_v);
842  }
843 
844  /*  */
845 
846  function unescapeNtripleUTF($v) {
847    if (strpos($v, '\\') === false) return $v;
848    $mappings = array('t' => "\t", 'n' => "\n", 'r' => "\r", '\"' => '"', '\'' => "'");
849    foreach ($mappings as $in => $out) {
850      $v = preg_replace('/\x5c([' . $in . '])/', $out, $v);
851    }
852    if (strpos(strtolower($v), '\u') === false) return $v;
853    while (preg_match('/\\\(U)([0-9A-F]{8})/', $v, $m) || preg_match('/\\\(u)([0-9A-F]{4})/', $v, $m)) {
854      $no = hexdec($m[2]);
855                if ($no < 128) $char = chr($no);
856      else if ($no < 2048) $char = chr(($no >> 6) + 192) . chr(($no & 63) + 128);
857      else if ($no < 65536) $char = chr(($no >> 12) + 224) . chr((($no >> 6) & 63) + 128) . chr(($no & 63) + 128);
858                else if ($no < 2097152) $char = chr(($no >> 18) + 240) . chr((($no >> 12) & 63) + 128) . chr((($no >> 6) & 63) + 128) . chr(($no & 63) + 128);
859      else $char= '';
860      $v = str_replace('\\' . $m[1] . $m[2], $char, $v);
861    }
862    return $v;
863  }
864 
865  /*  */
866 
867  function xPlaceholder($v) {
868    //if ($r = $this->x('(\?|\$)\{([^\}]+)\}', $v)) {
869    if ($r = $this->x('(\?|\$)', $v)) {
870      if (preg_match('/(\{(?:[^{}]+|(?R))*\})/', $r[2], $m) && strpos(trim($r[2]), $m[1]) === 0) {
871        $ph = substr($m[1], 1, -1);
872        $rest = substr(trim($r[2]), strlen($m[1]));
873        if (!isset($this->r['placeholders'])) $this->r['placeholders'] = array();
874        if (!in_array($ph, $this->r['placeholders'])) $this->r['placeholders'][] = $ph;
875        return array(array('value' => $ph, 'type' => 'placeholder'), $rest);
876      }
877    }
878    return array(0, $v);
879  }
880 
881  /*  */
882}
Note: See TracBrowser for help on using the repository browser.