source: Dev/branches/rest-dojo-ui/server/rdfapi/model/MemModel.php @ 303

Last change on this file since 303 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 37.5 KB
Line 
1<?php
2require_once RDFAPI_INCLUDE_DIR . 'model/Model.php';
3// ----------------------------------------------------------------------------------
4// Class: MemModel
5// ----------------------------------------------------------------------------------
6
7/**
8* A MemModel is an RDF Model, which is stored in the main memory.
9* This class provides methods for manipulating MemModels.
10*
11*
12*
13* @version  $Id: MemModel.php 425 2007-05-01 12:59:18Z cweiske $
14* @author Chris Bizer <chris@bizer.de>
15* @author Gunnar AAstrand Grimnes <ggrimnes@csd.abdn.ac.uk>
16* @author Radoslaw Oldakowski <radol@gmx.de>
17* @author Daniel Westphal <mail@d-westphal.de>
18* @author Tobias Gauß <tobias.gauss@web.de>
19*
20* @package model
21* @access       public
22*/
23
24class MemModel extends Model {
25
26        /**
27        * Triples of the MemModel
28        * @var          array
29        * @access       private
30        */
31        var $triples = array();
32
33        /**
34        * Array containing the search indices
35        * @var          array['INDEX_TYPE'][]['label'][]['PosInModel']
36        *
37        * @access   private
38        */
39        var $indexArr ;
40
41
42        /**
43        * depending on which index is used this variable is -1,0,1,2 or 3
44        *
45        * -1 : no index
46        *  0 : default indices over subject, predicate, object separate
47        *  1 : index over subject+predicate+object
48        *  2 : index over subject+predicate
49        *  3 : index over subject+object
50        *
51        * @var          int
52        * @access       private
53        */
54        var $indexed;
55
56
57
58        /**
59        * Array of namespaces
60        *
61        * @var     array
62        * @access       private
63        */
64        var $parsedNamespaces=array();
65
66
67
68        /**
69        * Constructor
70        * You can supply a base_uri
71        *
72        * @param string $baseURI
73        * @access       public
74        */
75        function MemModel($baseURI = NULL) {
76                $this->setBaseURI($baseURI);
77                $this->indexed = INDEX_TYPE;
78        }
79
80        /**
81        * Set a base URI for the MemModel.
82        * Affects creating of new resources and serialization syntax.
83        * If the URI doesn't end with # : or /, then a # is added to the URI.
84        * @param        string  $uri
85        * @access       public
86        */
87        function setBaseURI($uri) {
88
89                if ($uri != NULL) {
90                        $c = substr($uri, strlen($uri)-1 ,1);
91                        if (!($c=='#' || $c==':' || $c=='/' || $c=="\\"))
92                        $uri .= '#';
93                }
94                $this->baseURI = $uri;
95        }
96
97
98        /**
99        * Number of triples in the MemModel
100        *
101        * @return       integer
102        * @access       public
103        */
104        function size() {
105                return count($this->triples);
106        }
107
108        /**
109        * Checks if MemModel is empty
110        *
111        * @return       boolean
112        * @access       public
113        */
114        function isEmpty() {
115                if (count($this->triples) == 0) {
116                        return TRUE;
117                } else {
118                        return FALSE;
119                };
120        }
121
122
123        /**
124        * Adds a new triple to the MemModel without checking if the statement is already in the MemModel.
125        * So if you want a duplicate free MemModel use the addWithoutDuplicates() function (which is slower then add())
126        *
127        * @param                object Statement        $statement
128        * @access       public
129        * @throws       PhpError
130        */
131        function add($statement) {
132                if (!is_a($statement, 'Statement')) {
133                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: add): Statement expected.';
134                        trigger_error($errmsg, E_USER_ERROR);
135                }
136
137                if($this->indexed != -1){
138                        $this->triples[] = $statement;
139                        end($this->triples);
140                        $k=key($this->triples);
141                        if($this->indexed==0){
142                                // index over S
143                                $this->_indexOpr($statement,$k,4,1);
144                                // index over P
145                                $this->_indexOpr($statement,$k,5,1);
146                                // index over O
147                                $this->_indexOpr($statement,$k,6,1);
148                        }else{
149                                $this->_indexOpr($statement,$k,$this->indexed,1);
150                        }
151
152                }else{
153                        $this->triples[] = $statement;
154                }
155        }
156
157
158
159        /**
160        * Checks if a new statement is already in the MemModel and adds the statement, if it is not in the MemModel.
161        * addWithoutDuplicates() is significantly slower then add().
162        * Retruns TRUE if the statement is added.
163        * FALSE otherwise.
164        *
165        * @param        object Statement        $statement
166        * @return    boolean
167        * @access       public
168        * @throws       PhpError
169        */
170        function addWithoutDuplicates($statement) {
171
172                if (!is_a($statement, 'Statement')) {
173                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: addWithoutDuplicates): Statement expected.';
174                        trigger_error($errmsg, E_USER_ERROR);
175                }
176
177                if (!$this->contains($statement)) {
178                        $this->add($statement);
179                        return true;
180                }else{
181                        return false;
182                }
183        }
184
185        /**
186        * Removes the triple from the MemModel.
187        * TRUE if the triple is removed.
188        * FALSE otherwise.
189        *
190        * @param                object Statement        $statement
191        * @return    boolean
192        * @access       public
193        * @throws       PhpError
194        */
195        function remove($statement) {
196
197                if (!is_a($statement, 'Statement')) {
198                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: remove): Statement expected.';
199                        trigger_error($errmsg, E_USER_ERROR);
200                }
201                if($this->indexed==-1){
202                        $pass=false;
203                        foreach($this->triples as $key => $value) {
204                                if ($this->matchStatement($value, $statement->subject(), $statement->predicate(), $statement->object())) {
205                                        unset($this->triples[$key]);
206                                        $pass= true;
207                                }
208                        }
209                        return $pass;
210                }else{
211                        $k= null;
212                        if($this->indexed==0){
213                                $pass=false;
214                                $del=false;
215                                while($del!=-1){
216                                        // index over S
217                                        $del=$this->_indexOpr($statement,$k,4,0);
218                                        // index over P
219                                        $this->_indexOpr($statement,$k,5,0);
220                                        // index over O
221                                        $this->_indexOpr($statement,$k,6,0);
222                                        if($del!=-1){
223                                                unset($this->triples[$del]);
224                                                $pass=true;
225                                        }
226                                }
227                                return $pass;
228                        }else{
229                                $pass=false;
230                                $del=false;
231                                while($del!=-1){
232                                        $del=$this->_indexOpr($statement,$k,$this->indexed,0);
233                                        if($del!=-1){
234                                                unset($this->triples[$del]);
235                                                $pass=true;
236                                        }
237                                }
238                                return $pass;
239                        }
240                }
241        }
242
243        /**
244        * Short Dump of the MemModel.
245        *
246        * @access       public
247        * @return       string
248        */
249        function toString() {
250                return 'MemModel[baseURI=' . $this->getBaseURI() . ';  size=' . $this->size() . ']';
251        }
252
253        /**
254        * Dumps of the MemModel including all triples.
255        *
256        * @access       public
257        * @return       string
258        */
259        function toStringIncludingTriples() {
260                $dump = $this->toString() . chr(13);
261                foreach($this->triples as $value) {
262                        $dump .= $value->toString() . chr(13);
263                }
264                return $dump;
265        }
266
267
268
269
270        /**
271        * Writes the RDF serialization of the MemModel as HTML.
272        *
273        * @access       public
274        */
275        function writeAsHtml() {
276                require_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_RDF);
277                $ser = new RdfSerializer();
278                $rdf =& $ser->serialize($this);
279                $rdf = htmlspecialchars($rdf, ENT_QUOTES);
280                $rdf = str_replace(' ', '&nbsp;', $rdf);
281                $rdf = nl2br($rdf);
282                echo $rdf;
283        }
284
285        /**
286        * Writes the RDF serialization of the MemModel as HTML table.
287        *
288        * @access       public
289        */
290        function writeAsHtmlTable() {
291                // Import Package Utility
292                include_once(RDFAPI_INCLUDE_DIR.PACKAGE_UTILITY);
293                $rdfUtil = new RDFUtil();
294                $rdfUtil->writeHTMLTable($this);
295        }
296
297
298        /**
299        * Writes the RDF serialization of the MemModel as HTML table.
300        *
301        * @access       public
302        * @return       string
303        */
304        function writeRdfToString() {
305                // Import Package Syntax
306                include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_RDF);
307                $ser = new RdfSerializer();
308                $rdf =& $ser->serialize($this);
309                return $rdf;
310        }
311
312
313        /**
314        * Saves the RDF,N3 or N-Triple serialization of the MemModel to a file.
315        * You can decide to which format the model should be serialized by using a
316        * corresponding suffix-string as $type parameter. If no $type parameter
317        * is placed this method will serialize the model to XML/RDF format.
318        * Returns FALSE if the MemModel couldn't be saved to the file.
319        *
320        * @access       public
321        * @param        string  $filename
322        * @param        string  $type
323        * @throws   PhpError
324        * @return       boolean
325        */
326        function saveAs($filename, $type ='rdf') {
327
328
329                // get suffix and create a corresponding serializer
330                if ($type=='rdf') {
331                        // Import Package Syntax
332                        include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_RDF);
333                        $ser=new RdfSerializer();
334                }elseif ($type=='nt') {
335                        // Import Package Syntax
336                        include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_N3);
337                        $ser=new NTripleSerializer();
338                }elseif ($type=='n3') {
339                        // Import Package Syntax
340                        include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_N3);
341                        $ser=new N3Serializer();
342                }else {
343                        print ('Serializer type not properly defined. Use the strings "rdf","n3" or "nt".');
344                        return false;
345                };
346
347                return $ser->saveAs($this, $filename);
348        }
349
350
351        /**
352        * Tests if the MemModel contains the given triple.
353        * TRUE if the triple belongs to the MemModel;
354        * FALSE otherwise.
355        *
356        * @param        object Statement        &$statement
357        * @return       boolean
358        * @access       public
359        */
360        function contains(&$statement) {
361
362                // no index ->linear contains
363                if ($this->indexed==-1){
364                        foreach($this->triples as $value) {
365                                if ($value->equals($statement)){
366                                        return TRUE; }
367                        }
368                        return false;
369                }
370                if ($this->indexed==0){
371                        $res = $this->_containsIndex($statement,4);
372                        return $res;
373                }else{
374                        return $this->_containsIndex($statement,$this->indexed);
375                }
376        }
377
378
379        /**
380        * Determine if all of the statements in a model are also contained in this MemModel.
381        * True if all of the statements in $model are also contained in this MemModel and false otherwise.
382        *
383        * @param        object Model    &$model
384        * @return       boolean
385        * @access       public
386        */
387        function containsAll(&$model) {
388
389                if (is_a($model, 'MemModel')) {
390
391                        foreach($model->triples as $statement)
392                        if(!$this->contains($statement))
393                        return FALSE;
394                        return TRUE;
395
396                }elseif (is_a($model, 'DbModel'))
397
398                return $model->containsAll($this);
399
400                $errmsg = RDFAPI_ERROR . '(class: MemModel; method: containsAll): Model expected.';
401                trigger_error($errmsg, E_USER_ERROR);
402        }
403
404        /**
405        * Determine if any of the statements in a model are also contained in this MemModel.
406        * True if any of the statements in $model are also contained in this MemModel and false otherwise.
407        *
408        * @param        object Model    &$model
409        * @return       boolean
410        * @access       public
411        */
412        function containsAny(&$model) {
413
414                if (is_a($model, 'MemModel')) {
415
416                        foreach($model->triples as $modelStatement)
417                        if($this->contains($modelStatement))
418                        return TRUE;
419                        return FALSE;
420
421                }elseif (is_a($model, 'DbModel'))
422
423                return $model->containsAny($this);
424
425                $errmsg = RDFAPI_ERROR . '(class: MemModel; method: containsAll): Model expected.';
426                trigger_error($errmsg, E_USER_ERROR);
427        }
428
429
430        /**
431        * Builds a search index for the statements in the MemModel.
432        * The index is used by the find(),contains(),add() and remove() functions.
433        * Performance example using a model with 43000 statements on a Linux machine:
434        * Find without index takes 1.7 seconds.
435        * Indexing takes 1.8 seconds.
436        * Find with index takes 0.001 seconds.
437        * So if you want to query a model more then once, build a index first.
438        * The defaultindex is indices over subject, predicate, object seperate.
439        *
440        * mode = 0    : indices over subject,predicate,object (default)
441        * mode = 1       : index over subject+predicate+object
442        * mode = 2       : index over subject+predicate
443        * mode = 3       : index over subject+object
444        *
445        * @param     int $mode
446        * @access       public
447        */
448        function index($mode) {
449
450                unset($this->indexArr);
451                $this->indexArr=array();
452                switch($mode){
453                        // unset indices
454                        case -1:
455                        $this->indexed=-1;
456                        unset($this->indexArr);
457                        break;
458                        // index over SPO
459                        case 0:
460                        $this->indexed=0;
461                        foreach($this->triples as $k => $t) {
462                                // index over S
463                                $this->_indexOpr($t,$k,4,1);
464                                // index over P
465                                $this->_indexOpr($t,$k,5,1);
466                                // index over O
467                                $this->_indexOpr($t,$k,6,1);
468                        }
469                        break;
470                        default:
471                        $this->indexed=$mode;
472                        foreach($this->triples as $k => $t) {
473                                $this->_indexOpr($t,$k,$this->indexed,1);
474                        }
475                        break;
476                }
477        }
478
479
480        /**
481        * Returns       true if there is an index, false if not.
482        *
483        * @return       boolean
484        * @access       public
485        */
486        function isIndexed() {
487                if($this->indexed!=-1){
488                        return TRUE;
489                }else{
490                        return FALSE;
491                }
492        }
493
494        /**
495        * Returns the indextype:
496        * -1 if there is no index, 0 if there are indices over S,P,O(separate),
497        * 1 if there is an index over SPO, 2 if there is an index over SP and 3 if
498        * there is an index over SO.
499        *
500        * @return int
501        * @access public
502        *
503        */
504        function getIndexType(){
505                return $this->indexed;
506        }
507
508        /**
509        * General method to search for triples.
510        * NULL input for any parameter will match anything.
511        * Example:  $result = $m->find( NULL, NULL, $node );
512        * Finds all triples with $node as object.
513        * Returns an empty MemModel if nothing is found.
514        *
515        * @param        object Node     $subject
516        * @param        object Node     $predicate
517        * @param        object Node     $object
518        * @return       object MemModel
519        * @access       public
520        * @throws       PhpError
521        */
522
523        function find($subject,$predicate,$object) {
524
525                if (
526                (!is_a($subject, 'Resource') && $subject != NULL) ||
527                (!is_a($predicate, 'Resource') && $predicate != NULL) ||
528                (!is_a($object, 'Node') && $object != NULL)
529                ) {
530                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: find): Parameters must be subclasses of Node or NULL';
531                        trigger_error($errmsg, E_USER_ERROR);
532                }
533
534                $res = new MemModel($this->getBaseURI());
535                $res->indexed=-1;
536
537                if($this->isEmpty())
538                return $res;
539
540                if($subject == NULL && $predicate == NULL && $object == NULL)
541                return $this;
542
543                switch($this->indexed){
544                        case 1:
545                        if($subject!=NULL && $predicate != NULL && $object != NULL){
546                                $pos=$subject->getLabel().$predicate->getLabel().$object->getLabel();
547                                return $this->_findInIndex($pos,$subject,$predicate,$object,1);
548                        }else{
549                                break;
550                        }
551
552                        case 2:
553                        if($subject!=NULL && $predicate != NULL){
554                                $pos=$subject->getLabel().$predicate->getLabel();
555                                return $this->_findInIndex($pos,$subject,$predicate,$object,2);
556                        }else{
557                                break;
558                        }
559
560                        case 3:
561                        if($subject!=NULL && $object != NULL){
562                                $pos=$subject->getLabel().$object->getLabel();
563                                return $this->_findInIndex($pos,$subject,$predicate,$object,3);
564                        }else{
565                                break;
566                        }
567                        case 0:
568                        if($subject!= null){
569                                $pos=$subject->getLabel();
570                                return $this->_findInIndex($pos,$subject,$predicate,$object,4);
571                        }
572                        if($predicate!= null){
573                                $pos=$predicate->getLabel();
574                                return $this->_findInIndex($pos,$subject,$predicate,$object,5);
575                        }
576                        if($object!= null){
577                                $pos=$object->getLabel();
578                                return $this->_findInIndex($pos,$subject,$predicate,$object,6);
579                        }
580                }
581                // if no index: linear search
582                foreach($this->triples as $value) {
583                        if ($this->matchStatement($value, $subject, $predicate, $object))
584                        $res->add($value);
585                }
586                return $res;
587
588        }
589
590
591
592
593
594        /**
595        * Method to search for triples using Perl-style regular expressions.
596        * NULL input for any parameter will match anything.
597        * Example:  $result = $m->find_regex( NULL, NULL, $regex );
598        * Finds all triples where the label of the object node matches the regular expression.
599        * Returns an empty MemModel if nothing is found.
600        *
601        * @param        string  $subject_regex
602        * @param        string  $predicate_regex
603        * @param        string  $object_regex
604        * @return       object MemModel
605        * @access       public
606        */
607        function findRegex($subject_regex, $predicate_regex, $object_regex) {
608
609                $res = new MemModel($this->getBaseURI());
610
611                if($this->size() == 0)
612                return $res;
613
614                if($subject_regex == NULL && $predicate_regex == NULL && $object_regex == NULL)
615                return $this;
616
617                foreach($this->triples as $value) {
618                        if (
619                        ($subject_regex == NULL || preg_match($subject_regex, $value->subj->getLabel())) &&
620                        ($predicate_regex == NULL || preg_match($predicate_regex, $value->pred->getLabel())) &&
621                        ($object_regex == NULL || preg_match($object_regex, $value->obj->getLabel()))
622                        ) $res->add($value);
623                }
624
625                return $res;
626
627        }
628
629        /**
630        * Returns all tripels of a certain vocabulary.
631        * $vocabulary is the namespace of the vocabulary inluding a # : / char at the end.
632        * e.g. http://www.w3.org/2000/01/rdf-schema#
633        * Returns an empty MemModel if nothing is found.
634        *
635        * @param        string  $vocabulary
636        * @return       object MemModel
637        * @access       public
638        */
639        function findVocabulary($vocabulary) {
640
641                if($this->size() == 0)
642                return new MemModel();
643                if($vocabulary == NULL || $vocabulary == '')
644                return $this;
645
646                $res = new MemModel($this->getBaseURI());
647                if($this->indexed==0){
648                        foreach($this->indexArr[5] as $key => $value){
649                                $pos=strpos($key,'#')+1;
650                                if(substr($key,0,$pos)==$vocabulary){
651                                        for($i=1;$i<=$value[0];$i++){
652                                                $res->add($this->triples[$value[$i]]);
653                                        }
654                                }
655                        }
656                        return $res;
657                }else{
658                        // Import Package Utility
659                        include_once(RDFAPI_INCLUDE_DIR.PACKAGE_UTILITY);
660                        foreach($this->triples as $value) {
661                                if (RDFUtil::getNamespace($value->getPredicate()) == $vocabulary)
662                                $res->add($value);
663                        }
664                        return $res;
665                }
666        }
667
668        /**
669        * Searches for triples and returns the first matching statement.
670        * NULL input for any parameter will match anything.
671        * Example:  $result = $m->findFirstMatchingStatement( NULL, NULL, $node );
672        * Returns the first statement of the MemModel where the object equals $node.
673        * Returns an NULL if nothing is found.
674        * You can define an offset to search for. Default = 0
675        *
676        * @param        object Node     $subject
677        * @param        object Node     $predicate
678        * @param        object Node     $object
679        * @param        integer $offset
680        * @return       object Statement
681        * @access       public
682        */
683        function findFirstMatchingStatement($subject, $predicate, $object, $offset = 0) {
684
685                $currentOffset = 0;
686                for($i=0;$i<=$offset;$i++)
687                {
688                        $res = $this->findFirstMatchOff($subject, $predicate, $object, $currentOffset);
689                        $currentOffset=$res+1;
690                }
691                if ($res != -1) {
692                        return $this->triples[$res];
693                } else {
694                        return NULL;
695                }
696        }
697
698
699
700
701        /**
702        * Searches for triples and returns the first matching statement from a given offset.
703        * This method is used by the util/findIterator. NULL input for any parameter will match anything.
704        * Example:  $result = $m->findFirstMatchingStatement( NULL, NULL, $node, $off );
705        * Returns the position of the first statement of the MemModel where the object equals $node from the given
706        * offset.
707        * Returns an -1 if nothing is found.
708        *
709        * @param        object Node     $subject
710        * @param        object Node     $predicate
711        * @param        object Node     $object
712        * @param int         $off
713        * @return       int
714        * @access       private
715        */
716        function findFirstMatchOff($subject,$predicate, $object,$off) {
717
718                if (
719                (!is_a($subject, 'Resource') && $subject != NULL) ||
720                (!is_a($predicate, 'Resource') && $predicate != NULL) ||
721                (!is_a($object, 'Node') && $object != NULL)
722                ) {
723                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: find): Parameters must be subclasses of Node or NULL';
724                        trigger_error($errmsg, E_USER_ERROR);
725                }
726
727                $match=-1;
728                $ind=$this->indexed;
729                if($subject == NULL && $predicate == NULL && $object == NULL)
730                {
731                        foreach ($this->triples as $key => $statement)
732                        {
733                                if ($key >= $off)
734                                        return $key;
735                        }
736                        return -1;
737                }
738
739                switch($ind){
740                        case 1:
741                        if($subject!=NULL && $predicate != NULL && $object != NULL){
742                                $pos=$subject->getLabel().$predicate->getLabel().$object->getLabel();
743                                return $this->_findMatchIndex($pos,$subject,$predicate,$object,1,$off);
744                        }else{
745                                break;
746                        }
747
748                        case 2:
749                        if($subject!=NULL && $predicate != NULL){
750                                $pos=$subject->getLabel().$predicate->getLabel();
751                                return $this->_findMatchIndex($pos,$subject,$predicate,$object,2,$off);
752                        }else{
753                                break;
754                        }
755
756                        case 3:
757                        if($subject!=NULL && $object != NULL){
758                                $pos=$subject->getLabel().$object->getLabel();
759                                return $this->_findMatchIndex($pos,$subject,$predicate,$object,3,$off);
760                        }else{
761                                break;
762                        }
763                        case 0:
764                        if($subject!= null){
765                                $pos=$subject->getLabel();
766                                return $this->_findMatchIndex($pos,$subject,$predicate,$object,4,$off);
767                        }
768                        if($predicate!= null){
769                                $pos=$predicate->getLabel();
770                                return $this->_findMatchIndex($pos,$subject,$predicate,$object,5,$off);
771                        }
772                        if($object!= null){
773                                $pos=$object->getLabel();
774                                return $this->_findMatchIndex($pos,$subject,$predicate,$object,6,$off);
775                        }
776                        break;
777                }
778                // if no index: linear search
779                foreach($this->triples as $key => $value){
780                        if ($this->matchStatement($value, $subject, $predicate, $object)){
781                                if($off<=$key){
782                                        $match=$key;
783                                        break;
784                                }
785                        }
786                }
787                return $match;
788        }
789
790
791        /**
792        * Searches for triples and returns the number of matches.
793        * NULL input for any parameter will match anything.
794        * Example:  $result = $m->findCount( NULL, NULL, $node );
795        * Finds all triples with $node as object.
796        *
797        * @param        object Node     $subject
798        * @param        object Node     $predicate
799        * @param        object Node     $object
800        * @return       integer
801        * @access       public
802        */
803        function findCount($subject, $predicate, $object) {
804
805                $res = $this->find($subject, $predicate, $object);
806                return $res->size();
807
808        }
809
810
811        /**
812        * Perform an RDQL query on this MemModel.
813        * This method returns an associative array of variable bindings.
814        * The values of the query variables can either be RAP's objects (instances of Node)
815        * if $returnNodes set to TRUE, or their string serialization.
816        *
817        * @access       public
818        * @param string $queryString
819        * @param boolean $returnNodes
820        * @return  array   [][?VARNAME] = object Node  (if $returnNodes = TRUE)
821        *      OR  array   [][?VARNAME] = string
822        *
823        */
824        function rdqlQuery($queryString, $returnNodes = TRUE) {
825
826                // Import RDQL Package
827                include_once(RDFAPI_INCLUDE_DIR.PACKAGE_RDQL);
828
829                $parser = new RdqlParser();
830                $parsedQuery =& $parser->parseQuery($queryString);
831
832                // this method can only query this MemModel
833                // if another model was specified in the from clause throw an error
834                if (isset($parsedQuery['sources'][1])) {
835                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: rdqlQuery):';
836                        $errmsg .= ' this method can only query this MemModel';
837                        trigger_error($errmsg, E_USER_ERROR);
838                }
839
840                $engine = new RdqlMemEngine();
841                $res =& $engine->queryModel($this, $parsedQuery, $returnNodes);
842
843                return $res;
844        }
845
846        /**
847        * Perform an RDQL query on this MemModel.
848        * This method returns an RdqlResultIterator of variable bindings.
849        * The values of the query variables can either be RAP's objects (instances of Node)
850        * if $returnNodes set to TRUE, or their string serialization.
851        *
852        * @access       public
853        * @param string $queryString
854        * @param boolean $returnNodes
855        * @return  object RdqlResultIterator = with values as object Node  (if $returnNodes = TRUE)
856        *      OR  object RdqlResultIterator = with values as strings if (if $returnNodes = FALSE)
857        *
858        */
859        function rdqlQueryAsIterator($queryString, $returnNodes = TRUE) {
860                // Import RDQL Package
861                include_once(RDFAPI_INCLUDE_DIR.PACKAGE_RDQL);
862                return new RdqlResultIterator($this->rdqlQuery($queryString, $returnNodes));
863        }
864
865        /**
866        * General method to replace nodes of a MemModel.
867        * NULL input for any parameter will match nothing.
868        * Example:  $m->replace($node, NULL, $node, $replacement);
869        * Replaces all $node objects beeing subject or object in
870        * any triple of the MemModel with the $needle node.
871        *
872        * @param        object Node     $subject
873        * @param        object Node     $predicate
874        * @param        object Node     $object
875        * @param        object Node     $replacement
876        * @access       public
877        * @throws       PhpError
878        */
879        function replace($subject, $predicate, $object, $replacement) {
880
881                if (
882                (!is_a($replacement, 'Node')) ||
883                (!is_a($subject, 'Resource') && $subject != NULL) ||
884                (!is_a($predicate, 'Resource') && $predicate != NULL) ||
885                (!is_a($object, 'Node') && $object != NULL)
886                ) {
887                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: replace): Parameters must be subclasses of Node or NULL';
888                        trigger_error($errmsg, E_USER_ERROR);
889                }
890
891                if($this->size() == 0)
892                break;
893                foreach($this->triples as $key => $value) {
894                        if ($this->triples[$key]->subj->equals($subject)) {
895                                $this->triples[$key]->subj = $replacement;
896                        }
897                        if ($this->triples[$key]->pred->equals($predicate))
898                        $this->triples[$key]->pred = $replacement;
899                        if ($this->triples[$key]->obj->equals($object))
900                        $this->triples[$key]->obj = $replacement;
901
902                }
903                $this->index($this->indexed);
904        }
905
906
907        /**
908        * Internal method that checks, if a statement matches a S, P, O or NULL combination.
909        * NULL input for any parameter will match anything.
910        *
911        * @param        object Statement        $statement
912        * @param        object Node     $subject
913        * @param        object Node     $predicate
914        * @param        object Node     $object
915        * @return       boolean
916        * @access       private
917        */
918        function matchStatement($statement, $subject, $predicate, $object)  {
919
920                if(($subject != NULL) AND !($statement->subj->equals($subject)))
921                return false;
922
923                if($predicate != NULL && !($statement->pred->equals($predicate)))
924                return false;
925
926                if($object != NULL && !($statement->obj->equals($object)))
927                return false;
928
929                return true;
930        }
931
932
933
934
935        /**
936        * Checks if two models are equal.
937        * Two models are equal if and only if the two RDF graphs they represent are isomorphic.
938        *
939        * @access       public
940        * @param                object  model &$that
941        * @throws    phpErrpr
942        * @return       boolean
943        */
944
945        function equals(&$that)  {
946
947                if (!is_a($that, 'Model')) {
948                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: equals): Model expected.';
949                        trigger_error($errmsg, E_USER_ERROR);
950                }
951
952                if ($this->size() != $that->size())
953                return FALSE;
954                /*
955                if (!$this->containsAll($that))
956                return FALSE;
957                return TRUE;
958                */
959                include_once(RDFAPI_INCLUDE_DIR. "util/ModelComparator.php");
960                return ModelComparator::compare($this,$that);
961        }
962
963        /**
964        * Returns a new MemModel that is the set-union of the MemModel with another model.
965        * Duplicate statements are removed. If you want to allow duplicates, use addModel() which is much faster.
966        *
967        * The result of taking the set-union of two or more RDF graphs (i.e. sets of triples)
968        * is another graph, which we will call the merge of the graphs.
969        * Each of the original graphs is a subgraph of the merged graph. Notice that when forming
970        * a merged graph, two occurrences of a given uriref or literal as nodes in two different
971        * graphs become a single node in the union graph (since by definition they are the same
972        * uriref or literal) but blank nodes are not 'merged' in this way; and arcs are of course
973        * never merged. In particular, this means that every blank node in a merged graph can be
974        * identified as coming from one particular graph in the original set of graphs.
975        *
976        * Notice that one does not, in general, obtain the merge of a set of graphs by concatenating
977        * their corresponding N-triples documents and constructing the graph described by the merged
978        * document, since if some of the documents use the same node identifiers, the merged document
979        * will describe a graph in which some of the blank nodes have been 'accidentally' merged.
980        * To merge Ntriples documents it is necessary to check if the same nodeID is used in two or
981        * more documents, and to replace it with a distinct nodeID in each of them, before merging the
982        * documents. (Not implemented yet !!!!!!!!!!!)
983        *
984        * @param        object Model    $model
985        * @return       object MemModel
986        * @access       public
987        * @throws phpErrpr
988        *
989        */
990        function & unite(&$model)  {
991
992                if (!is_a($model, 'Model')) {
993                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: unite): Model expected.';
994                        trigger_error($errmsg, E_USER_ERROR);
995                }
996
997                $res = $this;
998
999                if (is_a($model, 'MemModel')) {
1000            require_once RDFAPI_INCLUDE_DIR . 'util/StatementIterator.php';
1001                        $stateIt=new StatementIterator($model);
1002                        while($statement=$stateIt->next())
1003                        {
1004                                $res->addWithoutDuplicates($statement);
1005                        }
1006                }
1007
1008                elseif (is_a($model, 'DbModel')) {
1009                        $memModel =& $model->getMemModel();
1010                        foreach($memModel->triples as $value)
1011                        $res->addWithoutDuplicates($value);
1012                }
1013
1014                return $res;
1015        }
1016
1017        /**
1018        * Returns a new MemModel that is the subtraction of another model from this MemModel.
1019        *
1020        * @param        object Model    $model
1021        * @return       object MemModel
1022        * @access       public
1023        * @throws phpErrpr
1024        */
1025
1026        function & subtract(&$model)  {
1027
1028                if (!is_a($model, 'Model')) {
1029                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: subtract): Model expected.';
1030                        trigger_error($errmsg, E_USER_ERROR);
1031                }
1032
1033                $res = $this;
1034
1035
1036                if (is_a($model, 'MemModel'))
1037                {
1038            require_once RDFAPI_INCLUDE_DIR . 'util/StatementIterator.php';
1039                        $stateIt=new StatementIterator($model);
1040                        while($statement=$stateIt->next())
1041                        {
1042                                $res->remove($statement);
1043                        }
1044                }
1045                elseif (is_a($model, 'DbModel'))
1046                {
1047                        $memModel =& $model->getMemModel();
1048                        foreach($memModel->triples as $value)
1049                        $res->remove($value);
1050                }
1051
1052
1053                return $res;
1054        }
1055
1056        /**
1057        * Returns a new MemModel containing all the statements which are in both this MemModel and another.
1058        *
1059        * @param        object Model    $model
1060        * @return       object MemModel
1061        * @access       public
1062        * @throws phpErrpr
1063        */
1064        function & intersect(&$model)  {
1065
1066                if (!is_a($model, 'Model')) {
1067                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: intersect: Model expected.';
1068                        trigger_error($errmsg, E_USER_ERROR);
1069                }
1070
1071                $res = new MemModel($this->getBaseURI());
1072
1073                if (is_a($model, 'DbModel') || is_a($model, 'RDFSBModel'))
1074                {
1075                        $memModel =& $model->getMemModel();
1076                        foreach($memModel->triples as $value) {
1077                                if ($this->contains($value))
1078                                $res->add($value);
1079                        }
1080                }
1081
1082                elseif (is_a($model, 'MemModel'))
1083                {
1084                        foreach($model->triples as $value) {
1085                                if ($this->contains($value))
1086                                $res->add($value);
1087                        }
1088                }
1089
1090
1091
1092                return $res;
1093        }
1094
1095
1096        /**
1097        * Adds another model to this MemModel.
1098        * Duplicate statements are not removed.
1099        * If you don't want duplicates, use unite().
1100        * If any statement of the model to be added to this model contains a blankNode
1101        * with an identifier already existing in this model, a new blankNode is generated.
1102        *
1103        * @param        object Model    $model
1104        * @access       public
1105        * @throws phpErrpr
1106        *
1107        */
1108        function addModel(&$model)  {
1109
1110                if (!is_a($model, 'Model')) {
1111                        $errmsg = RDFAPI_ERROR . '(class: MemModel; method: addModel): Model expected.';
1112                        trigger_error($errmsg, E_USER_ERROR);
1113                }
1114
1115                $blankNodes_tmp = array();
1116
1117                if (is_a($model, 'MemModel')) {
1118            require_once RDFAPI_INCLUDE_DIR . 'util/StatementIterator.php';
1119                        $stateIt=new StatementIterator($model);
1120                        while($statement=$stateIt->next())
1121                        {
1122                                $this->_addStatementFromAnotherModel($statement, $blankNodes_tmp);
1123                        };
1124                        $this->addParsedNamespaces($model->getParsedNamespaces());
1125                }
1126
1127                elseif (is_a($model, 'DbModel')) {
1128                        $memModel =& $model->getMemModel();
1129                        foreach($memModel->triples as $value)
1130                        $this->_addStatementFromAnotherModel($value, $blankNodes_tmp);
1131                }
1132                $this->index($this->indexed);
1133        }
1134
1135
1136        /**
1137        * Reifies the MemModel.
1138        * Returns a new MemModel that contains the reifications of all statements of this MemModel.
1139        *
1140        * @access       public
1141        * @return       object  MemModel
1142        */
1143        function & reify() {
1144                $res = new MemModel($this->getBaseURI());
1145
1146                $stateIt=$this->getStatementIterator();
1147                while($statement=$stateIt->next())
1148                {
1149                        $pointer =& $statement->reify($res);
1150                        $res->addModel($pointer);
1151                };
1152
1153                return $res;
1154        }
1155
1156        /**
1157        * Returns a StatementIterator for traversing the MemModel.
1158        * @access       public
1159        * @return       object  StatementIterator
1160        */
1161        function & getStatementIterator() {
1162                // Import Package Utility
1163        require_once RDFAPI_INCLUDE_DIR . 'util/StatementIterator.php';
1164
1165                $si = new StatementIterator($this);
1166                return $si;
1167        }
1168
1169        /**
1170        * Returns a FindIterator for traversing the MemModel.
1171        * @access       public
1172        * @return       object  FindIterator
1173        */
1174        function & findAsIterator($sub=null,$pred=null,$obj=null) {
1175                // Import Package Utility
1176        require_once RDFAPI_INCLUDE_DIR . 'util/FindIterator.php';
1177
1178                $if = new FindIterator($this,$sub,$pred,$obj);
1179                return $if;
1180        }
1181
1182        /**
1183        * Returns a FindIterator for traversing the MemModel.
1184        * @access       public
1185        * @return       object  FindIterator
1186        */
1187        function & iterFind($sub=null,$pred=null,$obj=null) {
1188                // Import Package Utility
1189        require_once RDFAPI_INCLUDE_DIR . 'util/IterFind.php';
1190
1191                $if = new IterFind($this,$sub,$pred,$obj);
1192                return $if;
1193        }
1194
1195
1196        /**
1197        * Returns the models namespaces.
1198        *
1199        * @author   Tobias Gauᅵ<tobias.gauss@web.de>
1200        * @access   public
1201        * @return   Array
1202        */
1203        function getParsedNamespaces(){
1204                if(count($this->parsedNamespaces)!=0){
1205                        return $this->parsedNamespaces;
1206                }else{
1207                        return false;
1208                }
1209        }
1210
1211
1212
1213        /**
1214        * Adds the namespaces to the model. This method is called by
1215        * the parser. !!!! addParsedNamespaces() not overwrites manual
1216        * added namespaces in the model !!!!
1217        *
1218        * @author   Tobias Gauᅵ<tobias.gauss@web.de>
1219        * @access   public
1220        * @param    Array $newNs
1221        */
1222        function addParsedNamespaces($newNs){
1223                if($newNs)
1224                $this->parsedNamespaces = $this->parsedNamespaces + $newNs;
1225        }
1226
1227
1228        /**
1229        * Adds a namespace and prefix to the model.
1230        *
1231        * @author   Tobias Gauᅵ<tobias.gauss@web.de>
1232        * @access   public
1233        * @param    String
1234        * @param    String
1235        */
1236        function addNamespace($prefix, $nmsp){
1237                $this->parsedNamespaces[$nmsp]=$prefix;
1238        }
1239
1240        /**
1241        * removes a single namespace from the model
1242        *
1243        * @author   Tobias Gauᅵ<tobias.gauss@web.de>
1244        * @access   public
1245        * @param    String $nmsp
1246        */
1247        function removeNamespace($nmsp){
1248                if(isset($this->parsedNamespaces[$nmsp])){
1249                        unset($this->parsedNamespaces[$nmsp]);
1250                        return true;
1251                }else{
1252                        return false;
1253                }
1254        }
1255
1256
1257
1258        /**
1259        * Close the MemModel and free up resources held.
1260        *
1261        * @access       public
1262        */
1263        function close() {
1264                unset( $this->baseURI );
1265                unset( $this->triples );
1266        }
1267
1268        // =============================================================================
1269        // *************************** helper functions ********************************
1270        // =============================================================================
1271        /**
1272        * Checks if $statement is in index
1273        *
1274        * @param  int $ind
1275        * @param  Statement &$statement
1276        * @return boolean
1277        * @access private
1278        */
1279        function _containsIndex(&$statement,$ind){
1280                switch($ind){
1281                        case 4:
1282                        $sub=$statement->getSubject();
1283                        $pos=$sub->getLabel();
1284                        break;
1285                        case 1:
1286                        $sub=$statement->getSubject();
1287                        $pred=$statement->getPredicate();
1288                        $obj=$statement->getObject();
1289                        $pos=$sub->getLabel().$pred->getLabel().$obj->getLabel();
1290                        break;
1291                        case 2:
1292                        $sub=$statement->getSubject();
1293                        $pred=$statement->getPredicate();
1294                        $pos=$sub->getLabel().$pred->getLabel();
1295                        break;
1296                        case 3:
1297                        $sub=$statement->getSubject();
1298                        $obj=$statement->getObject();
1299                        $pos=$sub->getLabel().$obj->getLabel();
1300                        break;
1301                }
1302
1303                if (!isset($this->indexArr[$ind][$pos]))
1304                return FALSE;
1305                foreach ($this->indexArr[$ind][$pos] as $key => $value) {
1306                        $t=$this->triples[$value];
1307                        if ($t->equals($statement))
1308                        return TRUE;
1309                }
1310                return FALSE;
1311        }
1312
1313
1314
1315
1316
1317        /**
1318        * finds a statement in an index. $pos is the Position in the index
1319        * and $ind the adequate searchindex
1320        *
1321        * @param    String            $pos
1322        * @param    Object Subject    &$subject
1323        * @param    Object Predicate  &$predicate
1324        * @param    Object Object        &$object
1325        * @param    int                          &ind
1326        * @return   MemModel          $res
1327        * @access   private
1328        */
1329        function _findInIndex($pos,&$subject,&$predicate,&$object,$ind){
1330                $res = new MemModel($this->getBaseURI());
1331                $res->indexed=-1;
1332                if (!isset($this->indexArr[$ind][$pos]))
1333                return $res;
1334                foreach($this->indexArr[$ind][$pos] as $key =>$value){
1335                        $t=$this->triples[$value];
1336                        if ($this->matchStatement($t,$subject,$predicate,$object))
1337                        $res->add($t);
1338                }
1339                return $res;
1340        }
1341        /**
1342        * adds/removes a statement into/from an index.
1343        * mode=0 removes the statement from the index;
1344        * mode=1 adds the statement into the index.
1345        * returns the statements position.
1346        *
1347        * @param Object Statement &$statement
1348        *       @param int              $k
1349        *       @param int              $ind
1350        * @param int                            $mode
1351        * @return int             $k
1352        * @access private
1353        */
1354        function _indexOpr(&$statement,$k,$ind,$mode){
1355                // determine position in adequate index
1356                switch($ind){
1357                        case 1:
1358                        $s=$statement->getSubject();
1359                        $p=$statement->getPredicate();
1360                        $o=$statement->getObject();
1361                        $pos=$s->getLabel().$p->getLabel().$o->getLabel();
1362                        break;
1363                        case 2:
1364                        $s=$statement->getSubject();
1365                        $p=$statement->getPredicate();
1366                        $pos=$s->getLabel().$p->getLabel();
1367                        break;
1368                        case 3:
1369                        $s=$statement->getSubject();
1370                        $o=$statement->getObject();
1371                        $pos=$s->getLabel().$o->getLabel();
1372                        break;
1373                        case 4:
1374                        $s=$statement->getSubject();
1375                        $pos=$s->getLabel();
1376                        break;
1377                        case 5:
1378                        $p=$statement->getPredicate();
1379                        $pos=$p->getLabel();
1380                        break;
1381                        case 6:
1382                        $o=$statement->getObject();
1383                        $pos=$o->getLabel();
1384                        break;
1385                }
1386                switch($mode){
1387                        // add in Index
1388                        case 1:
1389                        if(isset($this->indexArr[$ind][$pos])){
1390                                $this->indexArr[$ind][$pos][] = $k;
1391                        }else{
1392                                $this->indexArr[$ind][$pos][0] = $k;
1393                        }
1394                        break;
1395                        // remove from Index
1396                        case 0:
1397                        $subject=$statement->getSubject();
1398                        $predicate=$statement->getPredicate();
1399                        $object=$statement->getObject();
1400                        $k=-1;
1401                        if(!isset($this->indexArr[$ind][$pos])){
1402                                return -1;
1403                        }
1404                        $num=count($this->indexArr[$ind][$pos]);
1405                        foreach($this->indexArr[$ind][$pos] as $key => $value){
1406                                $t=$this->triples[$value];
1407                                if($this->matchStatement($t,$subject,$predicate,$object)){
1408                                        $k=$value;
1409                                        if($num==1){
1410                                                unset($this->indexArr[$ind][$pos]);
1411                                        }else{
1412                                                unset($this->indexArr[$ind][$pos][$key]);
1413                                        }
1414                                        return $k;
1415                                }
1416                        }
1417                        break;
1418                }
1419                return $k;
1420        }
1421
1422
1423        /**
1424        * finds next or previous matching statement.
1425        * Returns Position in model or -1 if there is no match.
1426        *
1427        *
1428        * @param            String
1429        * @param     object  Subject
1430        * @param            object      Predicate
1431        * @param     object  Object
1432        * @param     integer
1433        * @param     integer
1434        * @return       integer
1435        * @access       private
1436        */
1437        function _findMatchIndex($pos,&$s,&$p,&$o,$ind,$off){
1438                $match=-1;
1439                if (!isset($this->indexArr[$ind][$pos])) {
1440                        return $match;}
1441                        foreach($this->indexArr[$ind][$pos] as $key =>$value){
1442                                $t=$this->triples[$value];
1443                                if ($this->matchStatement($t,$s,$p,$o)){
1444                                        if($off <= $value){
1445                                                $match= $value;
1446                                                return $match;
1447                                        }
1448                                }
1449                        }
1450
1451                        return $match;
1452
1453        }
1454
1455
1456
1457
1458} // end: MemModel
1459
1460
1461?>
Note: See TracBrowser for help on using the repository browser.