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

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

rdfint

  • prefix non-standard methods rdfa::Data::_setValue with an underscore
  • Property svn:eol-style set to native
File size: 34.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 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 * <strong>NOTE: This method is a library specific extension to the RDF API and RDFa API.</strong>
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 * <strong>NOTE: This method is a library specific extension to the RDF API and RDFa API.</strong>
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 * <strong>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 * </strong>
441 */
442 public function parse( $toparse) {
443
444 // check type to parse
445 if ((is_object( $toparse)) &&
446 ('\\' . get_class( $toparse) == '\\rdfa\\SparqlQuery')) {
447
448 // receive RDF data from raw SPARQL query
449 $query = $toparse;
450 $parseSource = "SPARQL query";
451
452 $statement = $query->getStatement();
453 $debugMessage = "Parsing RDF data from SPARQL query\n" .
454 "Executing statement: \n" . $statement;
455 $this->debugger->sendMessage( $debugMessage, self::debugcontext);
456
457 $index = $query->run();
458 $newTriples = \ARC2::getTriplesFromIndex( $index);
459
460 } else {
461
462 // load RDF data from URI
463 $uri = $toparse;
464 $parseSource = "ARC parser";
465
466 $debugMessage = "Parsing RDF data from: $uri\n";
467 $this->debugger->sendMessage( $debugMessage, self::debugcontext);
468
469 $arcParser = \ARC2::getRDFParser();
470 $arcParser->parse( $uri);
471 $newTriples = $arcParser->getTriples();
472
473 }
474
475 // determine operation mode
476 $fMerge = (count( $this->aTriples) != 0);
477 if ($fMerge)
478 $operation = "merged";
479 else
480 $operation = "loaded";
481
482 // merge new triples into existing data
483 $this->_addTriples( $newTriples);
484
485 $debugMessage = count( $newTriples) . " triple(s) $operation from $parseSource\n";
486 foreach ($newTriples as $aTriple) {
487 $debugMessage .= $this->_debug_formatArcTriple( $aTriple)."\n";
488 }
489 if ($fMerge)
490 $debugMessage .= "\n" . count( $this->aTriples) . " triples total\n";
491 $this->debugger->sendMessage( $debugMessage, self::debugcontext);
492
493 } // public function parse
494
495 // --------------------------------------------------------
496
497 /**
498 * \name Basic API
499 */
500 /**@{ */ /***************** DOXYGEN GROUP START - Basic APIs */
501
502
503 /**
504 * Retrieves a list of all values expressed in the RDF Data that match the given subject and property.
505 *
506 * \param property property that the subject should be linked with
507 * \param value value that the specified property should have
508 *
509 * If no arguments are provided, all values from within the RDF data are returned.
510 */
511 public function getSubjects( $property = Null, $value = NULL) {
512
513 $predicate = $property;
514 $object = $value;
515 $aTriplesResult = $this->_filterTriples( NULL, $predicate, $object,
516 $debugmessage_filterresult);
517 // build result
518 $aresult = false;
519 foreach ($aTriplesResult as $aTriple) {
520 $aresult[]= $this->_shrink( $aTriple[ 's']);
521 }
522
523 // make result entries unique
524 if ($aresult !== false)
525 $aresult = array_values( array_unique( $aresult));
526
527 // build debug message
528 if (!$this->_calledFromOwnCode()) {
529 $formattedTriple = $this->_debug_formatTripleFromParms( NULL, $predicate, $object);
530 if (!$aresult)
531 $debugmessage = "No subjects found for: $formattedTriple\n";
532 else {
533 $debugmessage = count( $aresult) . " subjects found";
534 if ($formattedTriple != '')
535 $debugmessage .= " for: $formattedTriple";
536 $debugmessage .= "\n";
537 foreach( $aresult as $result) {
538 $debugmessage .= "$result\n";
539 }
540 }
541 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
542 self::debugcontext);
543
544 } // if (!$this->_calledFromOwnCode())
545
546 return $aresult;
547
548 } // public function getSubjects
549
550 // --------------------------------------------------------
551
552 /**
553 * Retrieves a list of all properties expressed in the RDF data that match the given subject.
554 *
555 * \param subject subject to be searched
556 *
557 * If a subject is not provided, all properties expressed in the RDF data are returned.
558 */
559 public function getProperties( $subject = Null) {
560
561 $aTriplesResult = $this->_filterTriples( $subject, Null, Null,
562 $debugmessage_filterresult);
563
564 // build result
565 $aresult = false;
566 foreach ($aTriplesResult as $aTriple) {
567 $aresult[]= $this->_shrink( $aTriple[ 'p']);
568 }
569
570 // make result entries unique
571 if ($aresult !== false)
572 $aresult = array_values( array_unique( $aresult));
573
574 // build debug message
575 if (!$this->_calledFromOwnCode()) {
576 if (!$aresult) {
577 if ( $subject = Null)
578 $debugmessage = "No properties found\n";
579 else
580 $debugmessage = "No properties found for subject: $subject\n";
581 }
582 else {
583
584 $debugmessage = count( $aresult) . " properties found for: $subject\n";
585 foreach( $aresult as $result) {
586 $debugmessage .= "$result\n";
587 }
588 }
589 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
590 self::debugcontext);
591
592 } // if (!$this->_calledFromOwnCode())
593
594 return $aresult;
595
596
597 } // public function getProperties
598
599 // --------------------------------------------------------
600
601 /**
602 * Retrieves an associative list of unique properties with their values expressed in the RDF data
603 * that match the given subject. All non-unique properties are <i>NOT</i> returned !
604 *
605 * \param subject subject to be searched
606 *
607 * If a subject isn't provided, all unique properties expressed in the RDF data are returned.
608 *
609 * <strong>NOTE: This method is a library specific extension to the RDF API and RDFa API.</strong>
610 */
611 public function _getUniqueProperties( $subject = Null) {
612
613 $aTriplesResult = $this->_filterTriples( $subject, Null, Null,
614 $debugmessage_filterresult);
615
616 // build result
617 $aresult = false;
618 $afound = array();
619 foreach ($aTriplesResult as $pos => $aTriple) {
620 // isolate predicate and check if it was already found
621 $thispredicate = $this->_shrink( $aTriple[ 'p']);
622 if (isset( $afound[ $thispredicate])) {
623 unset( $aresult[ $thispredicate]);
624 continue;
625 } else {
626 $afound[ $thispredicate] = true;
627 $aresult[ $thispredicate] = $this->_shrink( $aTriple[ 'o']);
628 }
629 }
630
631 // build debug message
632 if (!$this->_calledFromOwnCode()) {
633 if (!$aresult) {
634 if ( $subject = Null)
635 $debugmessage = "No unique properties found\n";
636 else
637 $debugmessage = "No unique properties found for subject: $subject\n";
638 }
639 else {
640
641 $debugmessage = count( $aresult) . " unique properties found for: $subject\n";
642 foreach( $aresult as $result) {
643 $debugmessage .= "$result\n";
644 }
645 }
646 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
647 self::debugcontext);
648
649 } // if (!$this->_calledFromOwnCode())
650
651 return $aresult;
652
653
654 } // public function _getUniqueProperties
655
656 // --------------------------------------------------------
657
658 /**
659 * Retrieves a list of all values expressed in the RDF data that match the given subject and property.
660 *
661 * \param subject subject to be searched
662 * \param property property to be searched
663 *
664 * If no arguments are provided, all values expressed in the RDF data are returned.
665 */
666 public function getValues( $subject = Null, $property = Null) {
667
668 $predicate = $property;
669 $aTriplesResult = $this->_filterTriples( $subject, $predicate, Null,
670 $debugmessage_filterresult);
671
672 // build result
673 $aresult = false;
674 foreach ($aTriplesResult as $aTriple) {
675 $aresult[]= $this->_shrink( $aTriple[ 'o']);
676 }
677
678 // make result entries unique
679 if ($aresult !== false)
680 $aresult = array_values( array_unique( $aresult));
681
682 // build debug message
683 if (!$this->_calledFromOwnCode()) {
684 $formattedTriple = $this->_debug_formatTripleFromParms( $subject, $predicate, Null);
685 if ($aresult === false) {
686 if ( $subject = Null)
687 $debugmessage = "No values found\n";
688 else
689 $debugmessage = "No values found for subject: $formattedTriple\n";
690 }
691 else {
692
693 $debugmessage = count( $aresult) . " values found for: $formattedTriple\n";
694 foreach( $aresult as $result) {
695 $debugmessage .= "$result\n";
696 }
697 }
698 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
699 self::debugcontext);
700
701 } // if (!$this->_calledFromOwnCode())
702
703 return $aresult;
704
705 } // public function getValues
706
707 // --------------------------------------------------------
708
709 /**
710 * Retrieves the first available value expressed in the RDF data that matches the given subject and property.
711 *
712 * \param subject subject to be searched
713 * \param property property to be searched
714 *
715 * If no arguments are provided, the first value expressed in the RDF data is returned.
716 *
717 * <strong>NOTE: This method is a library specific extension to the RDF API and RDFa API.</strong>
718 */
719 public function _getFirstValue( $subject = Null, $property = Null) {
720
721 $predicate = $property;
722 $aTriplesResult = $this->_filterTriples( $subject, $predicate, Null,
723 $debugmessage_filterresult);
724
725 // build result
726 $result = false;
727 foreach ($aTriplesResult as $aTriple) {
728 $result = $this->_shrink( $aTriple[ 'o']);
729 break;
730 }
731
732 // build debug message
733 if (!$this->_calledFromOwnCode()) {
734 $formattedTriple = $this->_debug_formatTripleFromParms( $subject, $predicate, Null);
735 if (!$result) {
736 if ($subject == Null)
737 $debugmessage = "No value found\n";
738 else
739 $debugmessage = "No value found for: $formattedTriple\n";
740 }
741 else {
742 $debugmessage = "Value $result found for: $formattedTriple\n";
743 $triplecount = count( $aTriplesResult);
744 if ($triplecount == 1)
745 $debugmessage .= "One value available";
746 else
747 $debugmessage .= "First of $triplecount values available";
748 }
749 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
750 self::debugcontext);
751
752 } // if (!$this->_calledFromOwnCode())
753
754 return $result;
755
756 } // public function _getFirstValue
757
758 // --------------------------------------------------------
759
760 /**
761 * Sets a property value for a subject.
762 *
763 * \param subject subject to get the property set
764 * \param property property to be added
765 * \param value value to be set for the property
766 * \param type the type of the value, either 'uri', 'literal' or 'bnode'
767 * (case-insensitive). Specifying the first character is sufficient.
768 * If not specified, strings starting with 'http://' are taken as a URI,
769 * otherwise as a literal
770 * \retval true property value set
771 * \retval false subject not found or invalid value type specified
772 *
773 * \see rdfa::Projection::set
774 *
775 * <strong>NOTE: This method is a library specific extension to the RDF API and RDFa API.</strong>
776 */
777
778 public function _setValue( $subject, $property, $value, $type = NULL) {
779
780 $predicate = $property;
781 $object = $value;
782
783 // insert code here
784
785 } // public function _setValue
786
787 /**@} */ /***************** DOXYGEN GROUP ENDS - Basic APIs */
788
789 // --------------------------------------------------------
790
791 /**
792 * \name Projection API
793 */
794 /**@{ */ /***************** DOXYGEN GROUP START - Projection APIs */
795
796 /**
797 * Retrieves a single Projection given a subject and an optional template.
798 * A template can be provided for the purpose of building the Projection in an application-specific way.
799 *
800 * \param subject subject to be searched
801 * \param template associative array( URI/CURIE => membername) as a template to be applied to the projection object
802 *
803 */
804 public function getProjection( $subject, $template = Null) {
805
806 if ($subject == Null)
807 return false;
808
809 if ((!$template == Null) && (!is_array( $template))) {
810 $this->debugger->sendError( "Invalid type specified as template (must be array) " . get_class() ."::getProjection", self::debugcontext);
811 return false;
812 }
813
814 $fLogMessages = (!$this->_calledFromOwnCode());
815 if (! $this->_subjectExists( $subject)) {
816echo "### no subject \n";
817 if ($fLogMessages) $this->debugger->sendMessage( "Cannot get projection for subject: $subject",
818 self::debugcontext);
819 $result = false;
820 } else {
821 if ($fLogMessages) $this->debugger->sendMessage( "Get projection for subject: $subject",
822 self::debugcontext);
823 $result = new \rdfa\Projection( $this, $subject, $template);
824 }
825
826 return $result;
827
828 } // public function getProjection
829
830 // --------------------------------------------------------
831
832 /**
833 * Retrieves a list of Projections given an optional property and value to match against.
834 * A template can be provided for the purpose of building the Projection in an application-specific way.
835 *
836 * \param property property that the subject of the projections should be linked with
837 * \param value value that the specified property should have
838 * \param template associative array( URI/CURIE => membername) as a template to be applied to the projection object
839 *
840 * If no arguments are provided, projections are created for all subjects from within the RDF data.
841 */
842 public function getProjections( $property = Null, $value = Null, $template = Null) {
843
844 if ((!$template == Null) && (!is_array( $template))) {
845 $this->debugger->sendError( "Invalid type specified as template (must be array) for " . get_class() ."::getProjections", self::debugcontext);
846 return false;
847 }
848
849 // providing log output about call
850 $predicate = $property;
851 $object = $value;
852 $fLogMessages = (!$this->_calledFromOwnCode());
853 $formattedTriple = $this->_debug_formatTripleFromParms( Null, $predicate, $object);
854 if ($formattedTriple != '')
855 $formattedTriple = " for: $formattedTriple";
856
857 $asubjects = $this->getSubjects( $property, $value);
858 if ($asubjects == false) {
859 if ($fLogMessages) $this->debugger->sendMessage( "Cannot get projections $formattedTriple",
860 self::debugcontext);
861 $aprojection = false;
862 } else {
863 $count = count( $asubjects);
864 if ($fLogMessages) $this->debugger->sendMessage( "Getting $count projections $formattedTriple",
865 self::debugcontext);
866 $aprojection = array();
867 foreach ($asubjects as $subject) {
868 $aprojection[] = new \rdfa\Projection( $this, $subject, $template);
869 }
870 }
871
872 return $aprojection;
873
874 } // public function getProjection
875
876 // --------------------------------------------------------
877
878 /**
879 * Retrieves a list of Projections based on a set of selection criteria.
880 * A template can be provided for the purpose of building the Projection in an application-specific way.
881 *
882 * \param query an associative array( URI/CURIE => value) specifying a multiple property filter
883 * \param template associative array( URI/CURIE => membername) as a template to be applied to the projection object
884 *
885 * If no arguments are provided, projections are created for all subjects from within the RDF data.
886 */
887 public function query( $query, $template = Null) {
888
889 if ((!$query == Null) && (!is_array( $query))) {
890 $this->debugger->sendError( "Invalid type specified as query (must be array) for " . get_class() ."::query", self::debugcontext);
891 return false;
892 }
893 if (count( $query) == 0) {
894 $this->debugger->sendError( "Empty query array specified " . get_class() ."::query", self::debugcontext);
895 return false;
896 }
897
898 if ((!$template == Null) && (!is_array( $template))) {
899 $this->debugger->sendError( "Invalid type specified as template (must be array) " . get_class() ."::query", self::debugcontext);
900 return false;
901 }
902
903 // providing log output about query
904 $fLogMessages = (!$this->_calledFromOwnCode());
905 $debugmessage = "Querying for projections\n";
906 foreach ($query as $property => $value) {
907 $debugmessage .= "filter: $property $value\n";
908 }
909 if ($fLogMessages) $this->debugger->sendMessage( "$debugmessage",
910 self::debugcontext);
911
912 // do initial search
913 list( $property, $value) = each( $query);
914 $asubjects = $this->getSubjects( $property, $value);
915 if ($asubjects == false)
916 return false;
917
918 // create projections for examination
919 $aprojection_test = array();
920 $count = count( $asubjects);
921 if ($fLogMessages) $this->debugger->sendMessage( "Getting $count projections for filter test",
922 self::debugcontext);
923 foreach ($asubjects as $subject) {
924 $aprojection_test[] = new \rdfa\Projection( $this, $subject, $template);
925 $debugmessage .= "$subject\n";
926 }
927
928 // determine which projections have to be filtered out
929 $aFilteredSubjects = array();
930 foreach ($aprojection_test as $projection) {
931 $subject = $projection->getSubject();
932 foreach ($query as $property => $value) {
933 $avalues = $projection->getAll( $property);
934 if ($avalues == false) {
935 // filter this projection: property not found
936 $aFilteredSubjects[ $subject] = "Property $property not found";
937 break;
938 } else {
939 if (array_search( $value, $avalues, true) === false) {
940 // filter this projection: specific value not found
941 $aFilteredSubjects[ $subject] = "Property $property does not have value: $value";
942 break;
943 }
944 }
945 }
946 }
947 $count = count( $aFilteredSubjects);
948 if ($count == 0) {
949 $debugmessage = "No projections filtered\n";
950 } else {
951 $debugmessage = "Filtering $count projections\n";
952 foreach ( $aFilteredSubjects as $subject => $reason) {
953 $debugmessage .= "$subject: $reason\n";
954 }
955 }
956
957 if ($fLogMessages) $this->debugger->sendMessage( "$debugmessage",
958 self::debugcontext);
959
960 // take over unfiltered projections
961 $aprojection = array();
962 foreach ($aprojection_test as $projection) {
963 if (array_key_exists( $projection->getSubject(), $aFilteredSubjects) === false) {
964 $aprojection[] = $projection;
965 } else {
966 unset( $projection);
967 }
968 }
969
970 // create log output
971 $count = count( $aprojection);
972 $debugmessage = "Returning $count projections \n";
973 foreach ($aprojection as $projection) {
974 $debugmessage .= "{$projection->getSubject()}\n";
975 }
976 if ($fLogMessages) $this->debugger->sendMessage( "$debugmessage",
977 self::debugcontext);
978 return $aprojection;
979
980 } // public function query
981
982 /**@} */ /***************** DOXYGEN GROUP ENDS - Projection APIs */
983
984 /**
985 * Returns a serialization of the triple data.
986 *
987 * \param type Supported RDF serialization MIME Media Types according to http://www.iana.org/assignments/media-types/index.html
988 *
989 * Currently supported mime type identifiers are:
990 *
991 * - application/rdf+xml
992 * - application/rdfxml
993 * - text/turtle
994 * - application/x-turtle
995 * - text/n3
996 * - application/json
997 *
998 * In addition to those, the internal type identifiers of this library can be used as well:
999 * - rdfxml
1000 * - turtle
1001 * - n3
1002 * - json
1003 *
1004 * <strong>NOTE: This method is a library specific extension to the RDF API and RDFa API.</strong>
1005 */
1006 public function _serialize( $type ) {
1007 // set the supported types and shortcut them to the ones we use in there
1008 $validTypes = array( 'application/rdf+xml' => 'rdfxml' ,
1009 'application/rdfxml' => 'rdfxml',
1010 'text/turtle' => 'turtle',
1011 'application/x-turtle' => 'turtle',
1012 'text/n3' => 'n3',
1013 'application/json' => 'json');
1014
1015 // check if explicit mime type is specified
1016 if (isset( $validTypes[ $type])) {
1017 $type = $validTypes[ $type];
1018 } else {
1019 // check if internal type is given
1020 $internalTypes = array_unique( array_flip( $validTypes));
1021 if (!isset( $internalTypes[ $type]))
1022 return false;
1023 }
1024
1025 switch ($type) {
1026
1027 case 'rdfxml':
1028 $ser = \ARC2::getRDFXMLSerializer();
1029 break;
1030
1031 case 'turtle':
1032 $ser = \ARC2::getTurtleSerializer();
1033 break;
1034
1035 case 'n3':
1036 $ser = \ARC2::getNTriplesSerializer();
1037 break;
1038
1039 case 'json':
1040 $ser = \ARC2::getRDFJSONSerializer();
1041 break;
1042
1043 } // switch ($type)
1044
1045 return $ser->getSerializedTriples( $this->aTriples);
1046
1047 } // public function _serialize
1048
1049} // class Data
1050
1051?>
Note: See TracBrowser for help on using the repository browser.