PageRenderTime 96ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/rdfapi-php/api/model/MemModel.php

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