source: php/trunk/classes/rdfa_Data.php@ 75

Last change on this file since 75 was 74, checked in by cla, 14 years ago

rdfint

  • moded general code for filtering triples and handling namespaces to core wrapper class
  • Property svn:eol-style set to native
File size: 32.5 KB
Line 
1<?php
2
3/* RDFInt.php - RDF Interfaces for PHP
4 * Copyright 2011 netlabs.org
5 * Author: Christian Langanke, Adrian Gschwend
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20namespace rdfa;
21
22/**
23 * \class Data
24 * \brief This class implements a RDF data class as described in the
25 * \c RDF \c API and \c RDFa \c API specs of W3C.
26 * \note Non-standard methods are marked as library specific extensions
27 * and the methodname is prepended by a single underscore character.
28 * For further information on differences to the W3C specifications,
29 * see the section
30 * \htmllink{page_w3cspecs.html,W3C Specifications Overview and Library Compatibility}
31 * \author Christian Langanke
32 * \author Adrian Gschwend
33 * \date 2011
34 */
35
36/*
37 * This class internally uses the ARC triple array format for storing RDF data:
38 *
39 * Array
40 * (
41 * [type] => --- 'triple' --- (others ???)
42 * [s] => --- uri ---
43 * [p] => --- uri ---
44 * [o] => --- uri or bnode or literal ---
45 * [s_type] => --- 'uri' or 'bnode' ---
46 * [p_type] => --- 'uri' --- (others ???)
47 * [o_type] => => --- 'uri' or 'bnode' oder 'literal' ---
48 * [o_datatype] => --- datatype or empty ---
49 * [o_lang] => --- lang code or empty ---
50 * )
51 *
52 */
53
54class Data {
55
56 /**
57 * Version of the class
58 */
59 const version = '1.0.0';
60 /**
61 * Name of the fDebug context
62 */
63 const debugcontext = 'RDFA_DATA';
64
65 private $debugger;
66 private $core;
67 private $aTriples;
68
69 // ---------------------------------------
70
71 /**
72 * Creates a data class instance.
73 * In order to access data, you have to call rdfa::Data::parse().
74 */
75 public function __construct() {
76
77 // setup debugger
78 $this->debugger = \fDebug::getInstance();
79
80 $this->core = new \rdfint_core\Core();
81
82 // initialize some vars
83 $this->aTriples = array();
84
85
86 } // public function __construct
87
88 // ########################################################
89 // private interface
90 // ########################################################
91
92 // debug formatting helpers
93
94 /**
95 * Return string with debug output, representing data from an ARC triple array.
96 * Values not being speciefied (==Null) are not included in the text.
97 * The object or value is enclosed in double quotes, if it is a literal
98 */
99 private function _debug_formatArcTriple( $aTriple) {
100 $subject = $aTriple[ 's'];
101 $predicate = $aTriple[ 'p'];
102 $object = $aTriple[ 'o'];
103 $objecttype = (isset( $aTriple[ 'o_type'])) ? $aTriple[ 'o_type'] : '';
104
105 $litSubject = ($subject == NULL) ? "" : $this->_shrinkFormatted( $subject);
106 $litPredicate = ($predicate == NULL) ? "" : $this->_shrinkFormatted( $predicate);
107
108 if ($object == NULL)
109 $litObject = "";
110 else {
111 if ($objecttype == 'literal')
112 $litObject = '"' . $object . '"';
113 else
114 $litObject = $this->_shrinkFormatted( $object);
115 }
116
117 $result = trim( "$litSubject $litPredicate $litObject");
118 return $result;
119 }
120
121 /**
122 * Return string with debug output, representing data the specified values.
123 * Values not being speciefied (==Null) are not included in the text.
124 * The object or value is enclosed in double quotes, if it is a literal
125 */
126 private function _debug_formatTripleFromParms( $subject, $predicate, $object) {
127 return $this->_debug_formatArcTriple( array( 's' => $subject,
128 'p' => $predicate,
129 'o' => $object));
130 }
131
132 // --------------------------------------------------------
133
134 /**
135 * Shrink URI to CURI, but return <URI> if mapping not successful.
136 */
137 private function _shrinkFormatted( $uri) {
138
139 $curie = $this->_shrink( $uri);
140 if ($curie == $uri)
141 $curie = "<$uri>";
142 return $curie;
143
144 } // private function _shrinkFormatted
145
146 // --------------------------------------------------------
147
148 /**
149 * Filters out requested triples by specified subject/predicate/object
150 * Returns array of matching triples in ARC triple array format
151 */
152 private function _filterTriples( $subject = NULL,
153 $predicate = NULL,
154 $object = NULL,
155 &$debugmessage_result) {
156
157 $aresult = $this->core->filterTriples( $this->aTriples, $subject, $predicate, $object);
158
159 // show result in debugger
160 $triplecount = count( $this->aTriples);
161 $resultcount = count( $aresult);
162 if ($resultcount == 0)
163 $debugmessage_result = "No match in $triplecount triples!";
164 else {
165 $debugmessage_result = "Matches in $triplecount triples: \n";
166 foreach ($aresult as $aTriple) {
167 $debugmessage_result .= $this->_debug_formatArcTriple( $aTriple)."\n";
168 }
169 }
170
171 return $aresult;
172
173 } // private function _filterTriples
174
175 // --------------------------------------------------------
176
177 /**
178 * Checks if a given subject exists in the RDF data.
179 */
180 private function _subjectExists( $subject) {
181
182 $uriSubject = $this->_shrink( $subject);
183 foreach ($this->aTriples as $aTriple) {
184 if ( $uriSubject == $this->_shrink( $aTriple[ 's']))
185 return true;
186 }
187
188 return false;
189
190 } // private function _subjectExists
191
192
193
194 // --------------------------------------------------------
195
196 // CURRENTLY NOT FULLY IMPLEMENTED
197
198 // adjust blank node IDs so that same blank nodes of a
199 // triple sets has the same id as in the currently contained
200 // triple set.
201 // NOTE: a blank nodes may not be adjusted if there are
202 // two different values for the same blank node in the two
203 // triple sets, as then the two blank nodes may represent a
204 // multivalue property
205
206 private function _adjustBlankNodes( $aTriplesToAdd) {
207
208
209// foreach ($this->aTriples as $aTriple) {
210// if ($aTriple[ 'o_type'] == 'bnode')
211// echo $aTriple[ 'o']."\n";
212// }
213
214
215 return $aTriplesToAdd;
216
217 }
218
219 // --------------------------------------------------------
220
221 // add an array of ARC triple arrays
222 // to the data hold by the instance
223 private function _addTriples( $aTriples) {
224 if (!is_array( $aTriples))
225 return;
226
227 // adjust blank node IDs first
228 $aTripleAdusted = $this->_adjustBlankNodes( $aTriples);
229
230 // add adjusted triples
231 foreach ($aTripleAdusted as $aTriple) {
232 $this->_addTriple( $aTriple);
233 }
234 } // private function _addTriples
235
236 // --------------------------------------------------------
237
238 // add an ARC triple array
239 // to the data hold by the instance
240 // the triple is only merged if not yet included !
241 private function _addTriple( $aTriple) {
242
243
244 if (!is_array( $aTriple))
245 return;
246 if ((isset( $aTriple['type']) &&
247 ($aTriple['type'] != 'triple')))
248 return;
249
250 // if triple is not contained, add it!
251 if (array_search( $aTriple, $this->aTriples) === false)
252 $this->aTriples[] = $aTriple;
253
254 } // private function _addTriple
255
256 // --------------------------------------------------------
257
258 /**
259 * Checks if callers caller is from own library code.
260 * Helps to reduce unwanted ddebug output
261 */
262 private function _calledFromOwnCode() {
263 // check for own namespace in backtrace
264 $trace = array_slice(debug_backtrace( false), 2, 1);
265 $class = (isset( $trace[0]['class'])) ? $trace[0]['class'] : '';
266 return (strpos( $class, 'rdfa\\') === 0);
267 } // private function _calledFromOwnCode
268
269 // ########################################################
270 // public interface
271 // ########################################################
272
273 /**
274 * \name Mapping API
275 */
276 /**@{ */ /***************** DOXYGEN GROUP START - Mapping APIs */
277
278 /**
279 * Sets short-hand IRI mappings that are used by the API to map URIs to CURIEs.
280 *
281 * \param prefix Namespace prefix of the mapping
282 * \param uriNamespace Namespace base URI of the mapping
283 * \retval void
284 *
285 * \note The return value
286 * - is not described in the \c RDFa \c API specification
287 * - should be a string in the \c RDF \c API, but the value is not described
288 */
289 public function setMapping( $prefix, $uriNamespace) {
290 $debugmessage = $this->core->setMapping( $prefix, $uriNamespace);
291 if ($debugmessage != false)
292 $this->debugger->sendMessage( $debugmessage,
293 self::debugcontext);
294 return;
295 } // public function setMapping
296
297 // --------------------------------------------------------
298
299 /**
300 * Resolves a CURI to a URI.
301 *
302 * If the prefix is not known then this method will return null.
303 *
304 * \param curie CURIE to be resolved to a URI
305 * \retval string URI
306 * \retval NULL Mapping could not be found
307 *
308 * \note This method is a library specific extension to the RDF API and RDFa API
309 */
310 public function _resolve( $curie) {
311
312 return $this->core->resolve( $curie);
313
314 } // public function _resolve
315
316 // --------------------------------------------------------
317
318 /**
319 * Shrinks a URI to a CURIE.
320 *
321 * If no mapping exists for the given URI, the URI is returned.
322 *
323 * \param uri URI to be shrinked to a CURIE
324 * \retval string CURIE or URI
325 *
326 * \note This method is a library specific extension to the RDF API and RDFa API
327 */
328 public function _shrink( $uri) {
329
330 return $this->core->shrink( $uri);
331
332 } // public function _shrink
333
334 /**@} */ /***************** DOXYGEN GROUP ENDS - Mapping APIs */
335
336 // --------------------------------------------------------
337
338 /**
339 * Parses RDF data from a URI.
340 *
341 * \param toparse Resource to parse from. This can be a URI or an object of SparqlQuery
342 * \retval boolean true: the parsed graph contains data
343 * \retval boolean false: the parsed graph contains no data
344 *
345 * \note
346 * - This method is defined for the RDF API, but a library specific extension to the RDFa API.
347 * - Parsing from a SPARQL CONSTRUCT query by using a SparqlQuery object, is a library specific
348 * extension to both the RDF API and RDFa API.
349 * - On all consecutive calls to parse, the newly parsed graph is merged into the existing graph.
350 * Such a feature is not described in the W3C specs
351 */
352 public function parse( $toparse) {
353
354 // check type to parse
355 if ((is_object( $toparse)) &&
356 ('\\' . get_class( $toparse) == '\\rdfa\\SparqlQuery')) {
357
358 // receive RDF data from raw SPARQL query
359 $query = $toparse;
360 $parseSource = "SPARQL query";
361
362 $statement = $query->getStatement();
363 $debugMessage = "Parsing RDF data from SPARQL query\n" .
364 "Executing statement: \n" . $statement;
365 $this->debugger->sendMessage( $debugMessage, self::debugcontext);
366
367 $newTriples = $query->run();
368
369 } else {
370
371 // load RDF data from URI
372 $uri = $toparse;
373 $parseSource = "ARC parser";
374
375 $debugMessage = "Parsing RDF data from: $uri\n";
376 $this->debugger->sendMessage( $debugMessage, self::debugcontext);
377
378 $core = new \rdfint_core\Core();
379 $newTriples = $core->parse( $uri);
380 }
381 // could something be parsed ?
382 $result = (count( $newTriples) > 0);
383
384 // determine operation mode
385 $fMerge = (count( $this->aTriples) != 0);
386 if ($fMerge)
387 $operation = "merged";
388 else
389 $operation = "loaded";
390
391 // merge new triples into existing data
392 $this->_addTriples( $newTriples);
393
394 $debugMessage = count( $newTriples) . " triple(s) $operation from $parseSource\n";
395 foreach ($newTriples as $aTriple) {
396 $debugMessage .= $this->_debug_formatArcTriple( $aTriple)."\n";
397 }
398 if ($fMerge)
399 $debugMessage .= "\n" . count( $this->aTriples) . " triples total\n";
400 $this->debugger->sendMessage( $debugMessage, self::debugcontext);
401
402 return $result;
403
404 } // public function parse
405
406 // --------------------------------------------------------
407
408 /**
409 * \name Basic API
410 */
411 /**@{ */ /***************** DOXYGEN GROUP START - Basic APIs */
412
413
414 /**
415 * Retrieves a list of all values expressed in the RDF Data that match the given subject and property.
416 *
417 * \param property Property that the subject should be linked with
418 * \param value Value that the specified property should have
419 * \retval array List of subjects
420 * \retval boolean false: the graph contains no data
421 *
422 * If no arguments are provided, all values from within the RDF data are returned.
423 */
424 public function getSubjects( $property = Null, $value = NULL) {
425
426 $predicate = $property;
427 $object = $value;
428 $aTriplesResult = $this->_filterTriples( NULL, $predicate, $object,
429 $debugmessage_filterresult);
430 // build result
431 $aresult = false;
432 foreach ($aTriplesResult as $aTriple) {
433 $aresult[]= $this->_shrink( $aTriple[ 's']);
434 }
435
436 // make result entries unique
437 if ($aresult !== false)
438 $aresult = array_values( array_unique( $aresult));
439
440 // build debug message
441 if (!$this->_calledFromOwnCode()) {
442 $formattedTriple = $this->_debug_formatTripleFromParms( NULL, $predicate, $object);
443 if (!$aresult)
444 $debugmessage = "No subjects found for: $formattedTriple\n";
445 else {
446 $debugmessage = count( $aresult) . " subjects found";
447 if ($formattedTriple != '')
448 $debugmessage .= " for: $formattedTriple";
449 $debugmessage .= "\n";
450 foreach( $aresult as $result) {
451 $debugmessage .= "$result\n";
452 }
453 }
454 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
455 self::debugcontext);
456
457 } // if (!$this->_calledFromOwnCode())
458
459 return $aresult;
460
461 } // public function getSubjects
462
463 // --------------------------------------------------------
464
465 /**
466 * Retrieves a list of all properties expressed in the RDF data that match the given subject.
467 *
468 * \param subject Subject to be searched
469 * \retval array List of properties
470 * \retval boolean false: the subject was not found
471 *
472 * If a subject is not provided, all properties expressed in the RDF data are returned.
473 */
474 public function getProperties( $subject = Null) {
475
476 $aTriplesResult = $this->_filterTriples( $subject, Null, Null,
477 $debugmessage_filterresult);
478
479 // build result
480 $aresult = false;
481 foreach ($aTriplesResult as $aTriple) {
482 $aresult[]= $this->_shrink( $aTriple[ 'p']);
483 }
484
485 // make result entries unique
486 if ($aresult !== false)
487 $aresult = array_values( array_unique( $aresult));
488
489 // build debug message
490 if (!$this->_calledFromOwnCode()) {
491 if (!$aresult) {
492 if ( $subject = Null)
493 $debugmessage = "No properties found\n";
494 else
495 $debugmessage = "No properties found for subject: $subject\n";
496 }
497 else {
498
499 $debugmessage = count( $aresult) . " properties found for: $subject\n";
500 foreach( $aresult as $result) {
501 $debugmessage .= "$result\n";
502 }
503 }
504 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
505 self::debugcontext);
506
507 } // if (!$this->_calledFromOwnCode())
508
509 return $aresult;
510
511
512 } // public function getProperties
513
514 // --------------------------------------------------------
515
516 /**
517 * Gets an associative list of unique properties with their values
518 * expressed in the RDF data that match the given subject.
519 *
520 * \param subject Subject to be searched
521 * \retval array Associative list of unqique properties and their values
522 * \retval boolean false: the subject could not be found
523 *
524 * If a subject isn't provided, all unique properties expressed in the RDF data are returned.
525 *
526 * \note
527 * - All non-unique properties are \c NOT returned !
528 * - This method is a library specific extension to the RDF API and RDFa API
529 */
530 public function _getUniqueProperties( $subject = Null) {
531
532 $aTriplesResult = $this->_filterTriples( $subject, Null, Null,
533 $debugmessage_filterresult);
534
535 // build result
536 $aresult = false;
537 $afound = array();
538 foreach ($aTriplesResult as $pos => $aTriple) {
539 // isolate predicate and check if it was already found
540 $thispredicate = $this->_shrink( $aTriple[ 'p']);
541 if (isset( $afound[ $thispredicate])) {
542 unset( $aresult[ $thispredicate]);
543 continue;
544 } else {
545 $afound[ $thispredicate] = true;
546 $aresult[ $thispredicate] = $this->_shrink( $aTriple[ 'o']);
547 }
548 }
549
550 // build debug message
551 if (!$this->_calledFromOwnCode()) {
552 if (!$aresult) {
553 if ( $subject = Null)
554 $debugmessage = "No unique properties found\n";
555 else
556 $debugmessage = "No unique properties found for subject: $subject\n";
557 }
558 else {
559
560 $debugmessage = count( $aresult) . " unique properties found for: $subject\n";
561 foreach( $aresult as $result) {
562 $debugmessage .= "$result\n";
563 }
564 }
565 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
566 self::debugcontext);
567
568 } // if (!$this->_calledFromOwnCode())
569
570 return $aresult;
571
572
573 } // public function _getUniqueProperties
574
575 // --------------------------------------------------------
576
577 /**
578 * Retrieves a list of all values expressed in the RDF data that match the given subject and property.
579 *
580 * \param subject Subject to be searched
581 * \param property Property to be searched
582 * \retval array List of values
583 * \retval boolean false: a matching subject was not found
584 *
585 * If no arguments are provided, all values expressed in the RDF data are returned.
586 */
587 public function getValues( $subject = Null, $property = Null) {
588
589 $predicate = $property;
590 $aTriplesResult = $this->_filterTriples( $subject, $predicate, Null,
591 $debugmessage_filterresult);
592
593 // build result
594 $aresult = false;
595 foreach ($aTriplesResult as $aTriple) {
596 $aresult[]= $this->_shrink( $aTriple[ 'o']);
597 }
598
599 // make result entries unique
600 if ($aresult !== false)
601 $aresult = array_values( array_unique( $aresult));
602
603 // build debug message
604 if (!$this->_calledFromOwnCode()) {
605 $formattedTriple = $this->_debug_formatTripleFromParms( $subject, $predicate, Null);
606 if ($aresult === false) {
607 if ( $subject = Null)
608 $debugmessage = "No values found\n";
609 else
610 $debugmessage = "No values found for subject: $formattedTriple\n";
611 }
612 else {
613
614 $debugmessage = count( $aresult) . " values found for: $formattedTriple\n";
615 foreach( $aresult as $result) {
616 $debugmessage .= "$result\n";
617 }
618 }
619 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
620 self::debugcontext);
621
622 } // if (!$this->_calledFromOwnCode())
623
624 return $aresult;
625
626 } // public function getValues
627
628 // --------------------------------------------------------
629
630 /**
631 * Retrieves the first available value expressed in the RDF data that matches the given subject and property.
632 *
633 * \param subject Subject to be searched
634 * \param property Property to be searched
635 * \retval string First value of the property
636 * \retval boolean false: the subject could not be found
637 *
638 * If no arguments are provided, the first value expressed in the RDF data is returned.
639 *
640 * \note This method is a library specific extension to the RDF API and RDFa API
641 */
642 public function _getFirstValue( $subject = Null, $property = Null) {
643
644 $predicate = $property;
645 $aTriplesResult = $this->_filterTriples( $subject, $predicate, Null,
646 $debugmessage_filterresult);
647
648 // build result
649 $result = false;
650 foreach ($aTriplesResult as $aTriple) {
651 $result = $this->_shrink( $aTriple[ 'o']);
652 break;
653 }
654
655 // build debug message
656 if (!$this->_calledFromOwnCode()) {
657 $formattedTriple = $this->_debug_formatTripleFromParms( $subject, $predicate, Null);
658 if (!$result) {
659 if ($subject == Null)
660 $debugmessage = "No value found\n";
661 else
662 $debugmessage = "No value found for: $formattedTriple\n";
663 }
664 else {
665 $debugmessage = "Value $result found for: $formattedTriple\n";
666 $triplecount = count( $aTriplesResult);
667 if ($triplecount == 1)
668 $debugmessage .= "One value available";
669 else
670 $debugmessage .= "First of $triplecount values available";
671 }
672 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
673 self::debugcontext);
674
675 } // if (!$this->_calledFromOwnCode())
676
677 return $result;
678
679 } // public function _getFirstValue
680
681 // --------------------------------------------------------
682
683 /**
684 * Sets a property value for a subject.
685 *
686 * \param subject Subject to get the property set as URI or CURIE
687 * \param property Property to be added as URI or CURIE
688 * \param value Value to be set for the property as URI, CURIE or literal value
689 * \param type The type of the value, either 'uri', 'literal' or 'bnode'
690 * (case-insensitive). Specifying the first character is sufficient.
691 * If not specified, strings starting with 'http://' are taken as a URI,
692 * strings starting with '_:' as a blank node, otherwise as a literal
693 * \retval boolean true: property value set \n
694 * false: subject not found or invalid value type specified
695 *
696 * \see rdfa::Projection::set
697 *
698 * \note This method is a library specific extension to the RDF API and RDFa API
699 */
700
701 public function _setValue( $subject, $property, $value, $type = NULL) {
702
703 $predicate = $property;
704 $object = $value;
705
706 // resolve namespace prefixes
707 $uriSubject = $this->_resolve( $subject);
708 $uriPredicate = $this->_resolve( $predicate);
709 $uriObject = $this->_resolve( $object);
710
711 // resolve method may return NULL, then use original value
712 $uriSubject = ($uriSubject === NULL) ? $subject : $uriSubject;
713 $uriPredicate = ($uriPredicate === NULL) ? $predicate : $uriPredicate;
714 $uriObject = ($uriObject === NULL) ? $object : $uriObject;
715
716 // check what type we have
717 // This is not clear in the API. It could be interpreted that the only acceptable value is a literal
718 // We have to check what the intention is and adjust it accordingly or enhance the specs
719 if ($type == null) {
720 if (preg_match('#^http://.?#', $value))
721 $type = 'uri';
722 elseif (preg_match('#/^_:.?/#', $value))
723 $type = 'bnode';
724 else
725 $type = 'literal';
726 }
727
728 if (!preg_match('#^(uri|bnode|literal)$#', strtolower($type)))
729 return false;
730
731 // construct the aTriple array
732 $aTriple = array();
733 $aTriple['type'] = 'triple';
734 $aTriple['s'] = $uriSubject;
735 $aTriple['p'] = $uriPredicate;
736 $aTriple['o'] = $uriObject;
737 $aTriple['s_type'] = 'uri';
738 $aTriple['p_type'] = 'uri';
739 $aTriple['o_type'] = strtolower($type);
740
741 $aTriple['o_datatype'] = ''; // data types, currently not supported by the API
742 $aTriple['o_lang'] = ''; // language, same same
743
744
745 $this->_addTriple( $aTriple);
746
747 return true;
748
749 } // public function _setValue
750
751 /**@} */ /***************** DOXYGEN GROUP ENDS - Basic APIs */
752
753 // --------------------------------------------------------
754
755 /**
756 * \name Projection API
757 */
758 /**@{ */ /***************** DOXYGEN GROUP START - Projection APIs */
759
760 /**
761 * Retrieves a single Projection given a subject and an optional template.
762 * A template can be provided for the purpose of building the Projection in an application-specific way.
763 *
764 * \param subject Subject to be searched
765 * \param template Associative array( URI/CURIE => membername) as a template to be applied to the projection object
766 * \retval rdfa::Projection The projection on the subject
767 * \retval boolean false: the subject was not found
768 *
769 */
770 public function getProjection( $subject, $template = Null) {
771
772 if ($subject == Null)
773 return false;
774
775 if ((!$template == Null) && (!is_array( $template))) {
776 $this->debugger->sendError( "Invalid type specified as template (must be array) " . get_class() ."::getProjection", self::debugcontext);
777 return false;
778 }
779
780 $fLogMessages = (!$this->_calledFromOwnCode());
781 if (! $this->_subjectExists( $subject)) {
782 if ($fLogMessages) $this->debugger->sendMessage( "Cannot get projection for subject: $subject",
783 self::debugcontext);
784 $result = false;
785 } else {
786 if ($fLogMessages) $this->debugger->sendMessage( "Get projection for subject: $subject",
787 self::debugcontext);
788 $result = new \rdfa\Projection( $this, $subject, $template);
789 }
790
791 return $result;
792
793 } // public function getProjection
794
795 // --------------------------------------------------------
796
797 /**
798 * Retrieves a list of Projections given an optional property and value to match against.
799 * A template can be provided for the purpose of building the Projection in an application-specific way.
800 *
801 * \param property Property that the subject of the projections should be linked with
802 * \param value Value that the specified property should have
803 * \param template Associative array( URI/CURIE => membername) as a template to be applied to the projection object
804 * \retval array List of rdfa::Projection as projections on the matching subjects
805 * \retval boolean false: a matching subject was not found
806 *
807 * If no arguments are provided, projections are created for all subjects from within the RDF data.
808 */
809 public function getProjections( $property = Null, $value = Null, $template = Null) {
810
811 if ((!$template == Null) && (!is_array( $template))) {
812 $this->debugger->sendError( "Invalid type specified as template (must be array) for " . get_class() ."::getProjections", self::debugcontext);
813 return false;
814 }
815
816 // providing log output about call
817 $predicate = $property;
818 $object = $value;
819 $fLogMessages = (!$this->_calledFromOwnCode());
820 $formattedTriple = $this->_debug_formatTripleFromParms( Null, $predicate, $object);
821 if ($formattedTriple != '')
822 $formattedTriple = " for: $formattedTriple";
823
824 $asubjects = $this->getSubjects( $property, $value);
825 if ($asubjects == false) {
826 if ($fLogMessages) $this->debugger->sendMessage( "Cannot get projections $formattedTriple",
827 self::debugcontext);
828 $aprojection = false;
829 } else {
830 $count = count( $asubjects);
831 if ($fLogMessages) $this->debugger->sendMessage( "Getting $count projections $formattedTriple",
832 self::debugcontext);
833 $aprojection = array();
834 foreach ($asubjects as $subject) {
835 $aprojection[] = new \rdfa\Projection( $this, $subject, $template);
836 }
837 }
838
839 return $aprojection;
840
841 } // public function getProjection
842
843 // --------------------------------------------------------
844
845 /**
846 * Retrieves a list of Projections based on a set of selection criteria.
847 * A template can be provided for the purpose of building the Projection in an application-specific way.
848 *
849 * \param query An associative array( URI/CURIE => value) specifying a multiple property filter
850 * \param template An associative array( URI/CURIE => membername) as a template to be applied to the projection object
851 * \retval array List of rdfa::Projection as projections on the matching subjects
852 * \retval boolean false: a matching subject was not found
853 *
854 * If no arguments are provided, projections are created for all subjects from within the RDF data.
855 */
856 public function query( $query, $template = Null) {
857
858 if ((!$query == Null) && (!is_array( $query))) {
859 $this->debugger->sendError( "Invalid type specified as query (must be array) for " . get_class() ."::query", self::debugcontext);
860 return false;
861 }
862 if (count( $query) == 0) {
863 $this->debugger->sendError( "Empty query array specified " . get_class() ."::query", self::debugcontext);
864 return false;
865 }
866
867 if ((!$template == Null) && (!is_array( $template))) {
868 $this->debugger->sendError( "Invalid type specified as template (must be array) " . get_class() ."::query", self::debugcontext);
869 return false;
870 }
871
872 // providing log output about query
873 $fLogMessages = (!$this->_calledFromOwnCode());
874 $debugmessage = "Querying for projections\n";
875 foreach ($query as $property => $value) {
876 $debugmessage .= "filter: $property $value\n";
877 }
878 if ($fLogMessages) $this->debugger->sendMessage( "$debugmessage",
879 self::debugcontext);
880
881 // do initial search
882 list( $property, $value) = each( $query);
883 $asubjects = $this->getSubjects( $property, $value);
884 if ($asubjects == false)
885 return false;
886
887 // examine properties
888 $aprojection_test = array();
889 $count = count( $asubjects);
890 if ($fLogMessages) $this->debugger->sendMessage( "Testing $count subjects",
891 self::debugcontext);
892 $aFilteredSubjects = array();
893 foreach ($asubjects as $subject) {
894 $debugmessage .= "$subject\n";
895 foreach ($query as $property => $value) {
896 $avalues = $this->getValues( $subject, $property);
897 if ($avalues == false) {
898 // filter this subject: property not found
899 $aFilteredSubjects[ $subject] = "Property $property not found";
900 break;
901 } else {
902 if (array_search( $value, $avalues, true) === false) {
903 // filter this projection: specific value not found
904 $aFilteredSubjects[ $subject] = "Property $property does not have value: $value";
905 break;
906 }
907 }
908 }
909 }
910
911 $count = count( $aFilteredSubjects);
912 if ($count == 0) {
913 $debugmessage = "No projections filtered\n";
914 } else {
915 $debugmessage = "Filtering $count subjects\n";
916 foreach ( $aFilteredSubjects as $subject => $reason) {
917 $debugmessage .= "$subject: $reason\n";
918 }
919 }
920
921 if ($fLogMessages) $this->debugger->sendMessage( "$debugmessage",
922 self::debugcontext);
923
924 // take over unfiltered projections
925 $aprojection = array();
926 foreach ($asubjects as $subject) {
927 if (array_key_exists( $subject, $aFilteredSubjects) === false)
928 $aprojection[] = new \rdfa\Projection( $this, $subject, $template);
929 }
930
931 // create projections on unfiltered subjects
932 foreach ($aprojection as $projection) {
933 $debugmessage .= "{$projection->getSubject()}\n";
934 }
935 $count = count( $aprojection);
936 $debugmessage = "Returning $count projections \n";
937
938 if ($fLogMessages) $this->debugger->sendMessage( "$debugmessage",
939 self::debugcontext);
940 return $aprojection;
941
942 } // public function query
943
944 /**@} */ /***************** DOXYGEN GROUP ENDS - Projection APIs */
945
946 /**
947 * Returns a serialization of the triple data.
948 *
949 * \param type Supported RDF serialization MIME Media Types according to http://www.iana.org/assignments/media-types/index.html
950 * \retval string Serialization of the graph data
951 * \retval boolean false: the serialization type is invalid
952 *
953 * Currently supported mime type identifiers are:
954 *
955 * - application/rdf+xml
956 * - application/rdfxml
957 * - text/turtle
958 * - application/x-turtle
959 * - text/n3
960 * - application/json
961 *
962 * In addition to those, the internal type identifiers of this library can be used as well:
963 * - rdfxml
964 * - turtle
965 * - n3
966 * - json
967 *
968 * \note This method is a library specific extension to the RDF API and RDFa API
969 */
970 public function _serialize( $type ) {
971
972 $core = new \rdfint_core\Core();
973 return $core->serialize( $this->aTriples, $type);
974
975 } // public function _serialize
976
977
978} // class Data
979
980?>
Note: See TracBrowser for help on using the repository browser.