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

Last change on this file since 312 was 312, checked in by jkraaijeveld, 13 years ago
File size: 19.2 KB
Line 
1<?php
2require_once RDFAPI_INCLUDE_DIR . 'util/Object.php';
3
4// ----------------------------------------------------------------------------------
5// Class: Model
6// ----------------------------------------------------------------------------------
7
8/**
9 * Abstract superclass of MemModel and DbModel. A model is a programming interface to an RDF graph.
10 * An RDF graph is a directed labeled graph, as described in http://www.w3.org/TR/rdf-mt/.
11 * It can be defined as a set of <S, P, O> triples, where P is a uriref, S is either
12 * a uriref or a blank node, and O is either a uriref, a blank node, or a literal.
13 *
14 *
15 * @version  $Id: Model.php 569 2008-05-19 05:24:39Z p_frischmuth $
16 * @author Radoslaw Oldakowski <radol@gmx.de>
17 * @author Daniel Westphal <mail@d-westphal.de>
18 *
19 * @package model
20 * @access      public
21 */
22class Model extends Object
23{
24    /**
25    * Base URI of the Model.
26    * Affects creating of new resources and serialization syntax.
27    *
28    * @var     string
29    * @access   private
30    */
31    var $baseURI;
32
33    /**
34    * Number of the last assigned bNode.
35    *
36    * @var     integer
37    * @access   private
38    */
39    var $bNodeCount;
40
41    /**
42    *   SparqlParser so we can re-use it
43    *   @var Parser
44    */
45    var $queryParser = null;
46
47
48
49    /**
50    * Notice for people who are used to work with older versions of RAP.
51    *
52    * @throws  PHPError
53    * @access   public
54    */
55    function Model()
56    {
57
58        $errmsg  = 'Since RAP 0.6 the class for manipulating memory models has been renamed to MemModel.';
59        $errmsg .= '<br>Sorry for this inconvenience.<br>';
60
61        trigger_error($errmsg, E_USER_ERROR);
62    }
63
64
65
66    /**
67    * Return current baseURI.
68    *
69    * @return  string
70    * @access   public
71    */
72    function getBaseURI()
73    {
74        return $this->baseURI;
75    }
76
77
78
79    /**
80    * Load a model from a file containing RDF, N3, N-Triples or a xhtml document containing RDF.
81    * This function recognizes the suffix of the filename (.n3 or .rdf) and
82    * calls a suitable parser, if no $type is given as string ("rdf" "n3" "nt");
83    * If the model is not empty, the contents of the file is added to this DbModel.
84    *
85    * @param    string  $filename
86    * @param    string  $type
87    * @param   boolean $stream
88    * @access   public
89    */
90    function load($filename, $type = NULL, $stream=false)
91    {
92        if ((isset($type)) && ($type =='n3') OR ($type =='nt')) {
93            // Import Package Syntax
94            include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_N3);
95            $parser = new N3Parser();
96        }elseif ((isset($type)) && ($type =='rdf')) {
97            // Import Package Syntax
98            include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_RDF);
99            $parser = new RdfParser();
100        }elseif ((isset($type)) && ($type =='grddl')) {
101            // Import Package Syntax
102            include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_GRDDL);
103            $parser = new GRDDLParser();
104        }elseif ((isset($type)) && ($type =='rss')) {
105            // Import Package Syntax
106            include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_RSS);
107            $parser = new RssParser();
108        }else {
109            // create a parser according to the suffix of the filename
110            // if there is no suffix assume the file to be XML/RDF
111            preg_match("/\.([a-zA-Z0-9_]+)$/", $filename, $suffix);
112            if (isset($suffix[1]) && (strtolower($suffix[1]) == 'n3' OR strtolower($suffix[1]) == 'nt')){
113                // Import Package Syntax
114                include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_N3);
115                $parser = new N3Parser();
116            }elseif (isset($suffix[1]) && (strtolower($suffix[1]) == 'htm' OR strtolower($suffix[1]) == 'html' OR strtolower($suffix[1]) == 'xhtml')){
117                    include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_GRDDL);
118                    $parser = new GRDDLParser();
119            }else{
120                // Import Package Syntax
121                include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_RDF);
122                $parser = new RdfParser();
123            }
124        };
125
126        if (($stream && $type=='rdf')||($stream && $type=='n3')) {
127                $temp=&$parser->generateModel($filename,false,$this);
128        } else{
129                $temp=&$parser->generateModel($filename);
130        }
131        $this->addModel($temp);
132        if($this->getBaseURI()== null)
133            $this->setBaseURI($temp->getBaseURI());
134    }
135
136        /**
137         * This method takes a string conatining data and adds the parsed data to this model.
138         *
139         * @param string $str The string containing the data to be parsed and loaded.
140         * @param type $type The type of the string, currently only 'json' is supported.
141         */
142        function loadFromString($str, $type) {
143               
144                switch ($type) {
145                        case 'json':
146                                include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_JSON);
147                                $parser = new JsonParser();
148                                break;
149                        case 'n3':
150                        case 'nt':
151                                include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_N3);
152                                $parser = new N3Parser();
153                                break;
154                        case 'rdf':
155                        case 'rdfxml':
156                        case 'xml':
157                                include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_RDF);
158                                $parser = new RdfParser();
159                                break;
160                        case 'grddl':
161                                include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_GRDDL);
162                                $parser = new GRDDLParser();
163                                break;
164                        case 'rss':
165                                include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_RSS);
166                                $parser = new RssParser();
167                                break;
168                        default:
169                                trigger_error('(class: Model; method: loadFromString): type ' . $type . 'is currently not supported',
170                                                E_USER_ERROR);
171                }
172               
173                if (($parser instanceof JsonParser) || ($parser instanceof N3Parser)) {
174                        $parser->generateModelFromString($str, $this);
175                } else {
176                        $temp = $parser->generateModel($str, false, $this);
177                       
178                        $this->addModel($temp);
179            if($this->getBaseURI() == null) {
180                $this->setBaseURI($temp->getBaseURI());
181            }
182                }
183        }
184
185    /**
186    * Adds a statement from another model to this model.
187    * If the statement to be added contains a blankNode with an identifier
188    * already existing in this model, a new blankNode is generated.
189    *
190    * @param    Object Statement   $statement
191    * @access   private
192    */
193    function _addStatementFromAnotherModel($statement, &$blankNodes_tmp)
194    {
195        $subject = $statement->getSubject();
196        $object = $statement->getObject();
197
198        if (is_a($subject, "BlankNode")) {
199            $label = $subject->getLabel();
200            if (!array_key_exists($label, $blankNodes_tmp))
201            {
202                if ($this->findFirstMatchingStatement($subject, NULL, NULL)
203                || $this->findFirstMatchingStatement(NULL, NULL, $subject))
204                {
205                $blankNodes_tmp[$label] = new BlankNode($this);
206                $statement->subj = $blankNodes_tmp[$label];
207                } else {
208                $blankNodes_tmp[$label] = $subject;
209                }
210            } else
211                $statement->subj = $blankNodes_tmp[$label];
212        }
213
214        if (is_a($object, "BlankNode")) {
215            $label = $object->getLabel();
216            if (!array_key_exists($label, $blankNodes_tmp))
217            {
218                if ($this->findFirstMatchingStatement($object, NULL, NULL)
219                || $this->findFirstMatchingStatement(NULL, NULL, $object))
220                {
221                $blankNodes_tmp[$label] = new BlankNode($this);
222                $statement->obj = $blankNodes_tmp[$label];
223                } else {
224                $blankNodes_tmp[$label] = $object;
225                }
226            } else
227                $statement->obj = $blankNodes_tmp[$label];
228        }
229        $this->add($statement);
230    }
231
232
233
234    /**
235    * Internal method, that returns a resource URI that is unique for the Model.
236    * URIs are generated using the base_uri of the DbModel, the prefix and a unique number.
237    * If no prefix is defined, the bNode prefix, defined in constants.php, is used.
238    *
239    * @param    string  $prefix
240    * @return   string
241    * @access   private
242    */
243    function getUniqueResourceURI($prefix = false)
244    {
245        static $bNodeCount;
246        if(!$bNodeCount)
247            $bNodeCount = 0;
248
249        if(!$prefix)
250            $prefix=BNODE_PREFIX;
251
252        return $prefix.++$bNodeCount;
253    }
254
255
256
257    /**
258    * Returns a ResModel with this model as baseModel. This is the same as
259    * ModelFactory::getResModelForBaseModel($this).
260    *
261    * @return   object  ResModel
262    * @access   public
263    */
264    function & getResModel()
265    {
266                $modelFactory = new ModelFactory();
267        return $modelFactory->getResModelForBaseModel($this);
268    }
269
270
271
272    /**
273    * Returns an OntModel with this model as baseModel.
274    * $vocabulary has to be one of the following constants (currently only one is supported):
275    * RDFS_VOCABULARY to select a RDFS Vocabulary.
276    *
277    * This is the same as ModelFactory::getOntModelForBaseModel($this, $vocabulary).
278    *
279    * @param   constant  $vocabulary
280    * @return   object  OntModel
281    * @access   public
282    */
283    function & getOntModel($vocabulary)
284    {
285                $modelFactory = new ModelFactory();
286        return $modelFactory->getOntModelForBaseModel($this, $vocabulary);
287    }
288
289
290
291    /**
292    * Searches for triples using find() and tracks forward blank nodes
293    * until the final objects in the retrieved subgraphs are all named resources.
294    * The method calls itself recursivly until the result is complete.
295    * NULL input for subject, predicate or object will match anything.
296    * Inputparameters are ignored for recursivly found statements.
297    * Returns a new MemModel or adds (without checking for duplicates)
298    * the found statements to a given MemModel.
299    * Returns an empty MemModel, if nothing is found.
300    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
301    * WARNING: This method can be slow with large models.
302    * NOTE:    Blank nodes are not renamed, they keep the same nodeIDs
303    *          as in the queried model!
304    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
305    *
306    * @author   Anton Koestlbacher <anton1@koestlbacher.de>
307    * @param    object Node     $subject
308    * @param    object Node     $predicate
309    * @param    object Node     $object
310    * @param    object MemModel $object
311    * @return   object MemModel
312    * @access   public
313    * @throws   PhpError
314    */
315    function findForward($subject, $predicate, $object, &$newModel = NULL)
316    {
317        if (!is_a($newModel, "MemModel"))
318        {
319            $newModel = New MemModel;
320        }
321
322        if (is_a($this, "DbModel"))
323        {
324            $model = $this;
325            $res   = $model->find($subject, $predicate, $object);
326            $it    = $res->getStatementIterator();
327        }
328        elseif (is_a($this, "MemModel")) {
329            $model = $this;
330            $it    = $model->findAsIterator($subject, $predicate, $object);
331        }
332        elseif (is_a($this, "ResModel")) {
333            $model = $this->model;
334            $it    = $model->findAsIterator($subject, $predicate, $object);
335        }
336
337        while ($it->hasNext())
338        {
339            $statement = $it->next();
340            $newModel->add($statement);
341            if (is_a($statement->object(),'BlankNode'))
342            {
343                $model->findForward($statement->object(), NULL, NULL, $newModel);
344            }
345        }
346        return $newModel;
347    }
348
349
350
351    /**
352    * Perform an RDQL query on this Model. Should work with all types of models.
353    * This method returns a MemModel containing the result statements.
354    * If $closure is set to TRUE, the result will additionally contain
355    * statements found by the findForward-method for blank nodes.
356    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
357    * WARNING: If called with $closure = TRUE this method
358    *          can be slow with large models.
359    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
360    *
361    * @author   Anton Kᅵtlbacher <anton1@koestlbacher.de>
362    * @author   code snippets taken from the RAP Netapi by Phil Dawes and Chris Bizer
363    * @access   public
364    * @param    string $queryString
365    * @param    boolean $closure
366    * @return   object MemModel
367    *
368    */
369    function & getMemModelByRDQL($queryString, $closure = FALSE)
370    {
371        require_once(RDFAPI_INCLUDE_DIR.PACKAGE_RDQL);
372        $parser = new RdqlParser();
373        $parsedQuery =& $parser->parseQuery($queryString);
374
375        // If there are variables used in the pattern but not
376        // in the select clause, add them to the select clause
377        foreach ($parsedQuery['patterns'] as $n => $pattern)
378        {
379            foreach ($pattern as $key => $val_1)
380            {
381                if ($val_1['value']{0}=='?')
382                {
383                    if (!in_array($val_1['value'],$parsedQuery['selectVars']))
384                    {
385                    array_push($parsedQuery['selectVars'],$val_1['value']);
386                    }
387                }
388            }
389        }
390
391        if (is_a($this, "DbModel"))
392        {
393            $engine = new RdqlDbEngine();
394            $model  = $this;
395        }
396        elseif (is_a($this, "MemModel"))
397        {
398            $engine = new RdqlMemEngine();
399            $model  = $this;
400        }
401        elseif (is_a($this, "ResModel"))
402        {
403            $engine = new RdqlMemEngine();
404            $model  = $this->model;
405        }
406
407        $res = $engine->queryModel($model,$parsedQuery,TRUE);
408        $rdqlIter = new RdqlResultIterator($res);
409        $newModel = new MemModel();
410
411        // Build statements from RdqlResultIterator
412        while ($rdqlIter->hasNext()) {
413            $result = $rdqlIter->next();
414            foreach ($parsedQuery['patterns'] as $n => $pattern)
415            {
416                if (substr($pattern['subject']['value'], 0, 1) == '?')
417                {
418                    $subj = $result[$pattern['subject']['value']];
419                }
420                else
421                {
422                    $subj = new Resource($pattern['subject']['value']);
423                }
424                if (substr($pattern['predicate']['value'], 0, 1) == '?')
425                {
426                    $pred = $result[$pattern['predicate']['value']];
427                }
428                else
429                {
430                    $pred = new Resource($pattern['predicate']['value']);
431                }
432
433                if (substr($pattern['object']['value'], 0, 1) == '?')
434                {
435                    $obj = $result[$pattern['object']['value']];
436                }
437                else
438                {
439                    if (isset($pattern['object']['is_literal']))
440                    {
441                        $obj = new Literal($pattern['object']['value']);
442                        $obj->setDatatype($pattern['object']['l_dtype']);
443                        $obj->setLanguage($pattern['object']['l_lang']);
444                    }
445                    else
446                    {
447                        $obj = new Resource($pattern['object']['value']);
448                    }
449                }
450
451                $statement = new Statement($subj,$pred,$obj);
452                $newModel->add($statement);
453
454                // findForward() Statements containing an eventually given blank node
455                // and add them to the result, if closure = true
456                if (is_a($statement->object(),'BlankNode') && $closure == True)
457                {
458                    $newModel = $model->findForward($statement->object(),NULL,NULL, $newModel);
459                }
460                if (is_a($statement->subject(),'BlankNode') && $closure == True)
461                {
462                    $newModel = $model->findForward($statement->subject(),NULL,NULL, $newModel);
463                }
464            }
465        }
466        return $newModel;
467    }
468
469
470
471    /**
472    * Alias for RDFUtil::visualiseGraph(&$model, $format, $short_prefix)
473    *
474    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
475    * Note: See RDFUtil for further Information.
476    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
477    *
478    * @author   Anton Kᅵtlbacher <anton1@koestlbacher.de>
479    * @param    string  $format
480    * @param    boolean $short_prefix
481    * @return   string, binary
482    * @access   public
483    * @throws   PhpError
484    */
485    function visualize($format = "dot", $short_prefix = TRUE)
486    {
487                $rdfUtil = new RDFUtil();
488        return $rdfUtil->visualizeGraph($this, $format, $short_prefix);
489    }
490
491
492    /**
493    * Performs a SPARQL query against a model. The model is converted to
494    * an RDF Dataset. The result can be retrived in SPARQL Query Results XML Format or
495    * as an array containing the variables an their bindings.
496    *
497    * @param  string $query      the sparql query string
498    * @param  string $resultform the result form ('xml' for SPARQL Query Results XML Format)
499    * @return string/array
500    */
501    function sparqlQuery($query, $resultform = false)
502    {
503        list($engine, $dataset) = $this->_prepareSparql();
504        return $engine->queryModel(
505            $dataset,
506            $this->_parseSparqlQuery($query),
507            $resultform
508        );
509    }//function sparqlQuery($query,$resultform = false)
510
511
512
513    /**
514    *   Prepares a sparql query and returns a prepared statement
515    *   that can be executed with data later on.
516    *
517    *   @param string $query Sparql query to prepare.
518    *   @return SparqlEngine_PreparedStatement  prepared statement object
519    */
520    function sparqlPrepare($query)
521    {
522        list($engine, $dataset) = $this->_prepareSparql();
523        return $engine->prepare(
524            $dataset,
525            $this->_parseSparqlQuery($query)
526         );
527    }//function sparqlPrepare($query)
528
529
530
531    /**
532    *   Prepares everything for SparqlEngine-usage
533    *   Loads the files, creates instances for SparqlEngine and
534    *   Dataset...
535    *
536    *   @return array First value is the sparql engine, second the dataset
537    */
538    function _prepareSparql()
539    {
540        require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlEngine.php';
541        require_once RDFAPI_INCLUDE_DIR . 'dataset/DatasetMem.php';
542
543        $dataset = new DatasetMem();
544        $dataset->setDefaultGraph($this);
545
546                $sparqlEngine = SparqlEngine::getInstance();
547               
548        return array(
549            $sparqlEngine->factory($this),
550            $dataset
551        );
552    }//function _prepareSparql()
553
554
555
556    /**
557    *   Parses an query and returns the parsed form.
558    *   If the query is not a string but a Query object,
559    *   it will just be returned.
560    *
561    *   @param $query mixed String or Query object
562    *   @return Query query object
563    *   @throws Exception If $query is no string and no Query object
564    */
565    function _parseSparqlQuery($query)
566    {
567        if ($this->queryParser === null) {
568            require_once RDFAPI_INCLUDE_DIR . 'sparql/SparqlParser.php';
569            $this->queryParser = new SparqlParser();
570        }
571        return $this->queryParser->parse($query);
572    }//function _parseSparqlQuery($query)
573
574} // end: Model
575
576?>
Note: See TracBrowser for help on using the repository browser.