source: Dev/branches/rest-dojo-ui/Demo/rdfapi/model/MemModel.php @ 312

Last change on this file since 312 was 312, checked in by jkraaijeveld, 13 years ago
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.