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

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

rdfint

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