PageRenderTime 61ms CodeModel.GetById 38ms RepoModel.GetById 0ms app.codeStats 0ms

/rdfapi-php/api/model/Model.php

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