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

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

rdfint

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