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

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

rdfint

  • all classes: added missing comments on return value
  • Projection::construct and rdfa::SparqlQuery: added missing comment on exceptions
  • Data::parse
    • added note on merge feature
    • added code to return boolean
  • Property svn:eol-style set to native
File size: 35.7 KB
Line 
1<?php
2
3/* RDFInt.php - RDF Interfaces for PHP
4 * Copyright 2011 netlabs.org
5 * Author: Christian Langanke, Adrian Gschwend
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20namespace rdfa;
21
22/**
23 * \class Data
24 * \brief This class implements a RDF data class as described in the
25 * \c RDF \c API and \c RDFa \c API specs of W3C.
26 * \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 * \retval void
347 *
348 * \note The return value
349 * - is not described in the \c RDFa \c API specification
350 * - should be a string in the \c RDF \c API, but the value is not described
351 */
352 public function setMapping( $prefix, $uriNamespace) {
353 $debugmessage = $this->_addNamespaceMapping( $prefix, $uriNamespace);
354 if ($debugmessage != false)
355 $this->debugger->sendMessage( $debugmessage,
356 self::debugcontext);
357 return;
358 } // public function setMapping
359
360 // --------------------------------------------------------
361
362 /**
363 * Resolves a CURI to a URI.
364 *
365 * If the prefix is not known then this method will return null.
366 *
367 * \param curie CURIE to be resolved to a URI
368 * \retval string URI
369 * \retval NULL Mapping could not be found
370 *
371 * \note This method is a library specific extension to the RDF API and RDFa API
372 */
373 public function _resolve( $curie) {
374
375 $replacecount = 1;
376 $uri = NULL;
377 if ($curie != NULL) {
378 if ($this->aNamespace != NULL) {
379 if ((strpos( $uri, ":/") !== false) ||
380 (strpos( $uri, "_:") === 0)) {
381 $uri = $curi;
382 } else {
383 // check for namespaces
384 foreach ($this->aNamespace as $prefix => $uriNamespace) {
385 // check for prefix match
386 $posPrefix = strpos( $curie, $prefix);
387 if ($posPrefix === 0) {
388 // replace prefix and bail out
389 $uri = str_replace( $prefix, $uriNamespace, $curie, $replacecount);
390 break;
391 }
392 } // foreach ($this->aNamespace
393 } // if ((strpos ...
394 } // if ($aNamespace != NULL) {
395 } // if ($uri != NULL) {
396
397 return $uri;
398
399 } // public function _resolve
400
401 // --------------------------------------------------------
402
403 /**
404 * Shrinks a URI to a CURIE.
405 *
406 * If no mapping exists for the given URI, the URI is returned.
407 *
408 * \param uri URI to be shrinked to a CURIE
409 * \retval string CURIE or URI
410 *
411 * \note This method is a library specific extension to the RDF API and RDFa API
412 */
413 public function _shrink( $uri) {
414
415 $replacecount = 1;
416 if ($uri != NULL) {
417 if ($this->aNamespace != NULL) {
418 if (strpos( $uri, ":/") !== false) {
419 foreach ($this->aNamespace as $prefix => $uriNamespace) {
420 // search namespace URI
421 $posNamespace = strpos( $uri, $uriNamespace);
422 if ($posNamespace === false)
423 continue;
424 // replace namespace URI and bail out
425 $uri = str_replace( $uriNamespace, $prefix, $uri, &$replacecount);
426 break;
427 } // foreach ($aNamespace
428 } // if (strpos( $uri, ":/") !== false)
429 } // if ($aNamespace != NULL) {
430 } // if ($uri != NULL) {
431
432 return $uri;
433
434 } // public function _shrink
435
436 /**@} */ /***************** DOXYGEN GROUP ENDS - Mapping APIs */
437
438 // --------------------------------------------------------
439
440 /**
441 * Parses RDF data from a URI.
442 *
443 * \param toparse Resource to parse from. This can be a URI or an object of SparqlQuery
444 * \retval boolean true: the parsed graph contains data
445 * \retval boolean false: the parsed graph contains no data
446 *
447 * \note
448 * - This method is defined for the RDF API, but a library specific extension to the RDFa API.
449 * - Parsing from a SPARQL CONSTRUCT query by using a SparqlQuery object, is a library specific
450 * extension to both the RDF API and RDFa API.
451 * - On all consecutive calls to parse, the newly parsed graph is merged into the existing graph.
452 * Such a feature is not described in the W3C specs
453 */
454 public function parse( $toparse) {
455
456 // check type to parse
457 if ((is_object( $toparse)) &&
458 ('\\' . get_class( $toparse) == '\\rdfa\\SparqlQuery')) {
459
460 // receive RDF data from raw SPARQL query
461 $query = $toparse;
462 $parseSource = "SPARQL query";
463
464 $statement = $query->getStatement();
465 $debugMessage = "Parsing RDF data from SPARQL query\n" .
466 "Executing statement: \n" . $statement;
467 $this->debugger->sendMessage( $debugMessage, self::debugcontext);
468
469 $index = $query->run();
470 $newTriples = \ARC2::getTriplesFromIndex( $index);
471
472 } else {
473
474 // load RDF data from URI
475 $uri = $toparse;
476 $parseSource = "ARC parser";
477
478 $debugMessage = "Parsing RDF data from: $uri\n";
479 $this->debugger->sendMessage( $debugMessage, self::debugcontext);
480
481 $arcParser = \ARC2::getRDFParser();
482 $arcParser->parse( $uri);
483 $newTriples = $arcParser->getTriples();
484
485 }
486 // could something be parsed ?
487 $result = (count( $newTriples) > 0);
488
489 // determine operation mode
490 $fMerge = (count( $this->aTriples) != 0);
491 if ($fMerge)
492 $operation = "merged";
493 else
494 $operation = "loaded";
495
496 // merge new triples into existing data
497 $this->_addTriples( $newTriples);
498
499 $debugMessage = count( $newTriples) . " triple(s) $operation from $parseSource\n";
500 foreach ($newTriples as $aTriple) {
501 $debugMessage .= $this->_debug_formatArcTriple( $aTriple)."\n";
502 }
503 if ($fMerge)
504 $debugMessage .= "\n" . count( $this->aTriples) . " triples total\n";
505 $this->debugger->sendMessage( $debugMessage, self::debugcontext);
506
507 return $result;
508
509 } // public function parse
510
511 // --------------------------------------------------------
512
513 /**
514 * \name Basic API
515 */
516 /**@{ */ /***************** DOXYGEN GROUP START - Basic APIs */
517
518
519 /**
520 * Retrieves a list of all values expressed in the RDF Data that match the given subject and property.
521 *
522 * \param property Property that the subject should be linked with
523 * \param value Value that the specified property should have
524 * \retval array List of subjects
525 * \retval boolean false: the graph contains no data
526 *
527 * If no arguments are provided, all values from within the RDF data are returned.
528 */
529 public function getSubjects( $property = Null, $value = NULL) {
530
531 $predicate = $property;
532 $object = $value;
533 $aTriplesResult = $this->_filterTriples( NULL, $predicate, $object,
534 $debugmessage_filterresult);
535 // build result
536 $aresult = false;
537 foreach ($aTriplesResult as $aTriple) {
538 $aresult[]= $this->_shrink( $aTriple[ 's']);
539 }
540
541 // make result entries unique
542 if ($aresult !== false)
543 $aresult = array_values( array_unique( $aresult));
544
545 // build debug message
546 if (!$this->_calledFromOwnCode()) {
547 $formattedTriple = $this->_debug_formatTripleFromParms( NULL, $predicate, $object);
548 if (!$aresult)
549 $debugmessage = "No subjects found for: $formattedTriple\n";
550 else {
551 $debugmessage = count( $aresult) . " subjects found";
552 if ($formattedTriple != '')
553 $debugmessage .= " for: $formattedTriple";
554 $debugmessage .= "\n";
555 foreach( $aresult as $result) {
556 $debugmessage .= "$result\n";
557 }
558 }
559 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
560 self::debugcontext);
561
562 } // if (!$this->_calledFromOwnCode())
563
564 return $aresult;
565
566 } // public function getSubjects
567
568 // --------------------------------------------------------
569
570 /**
571 * Retrieves a list of all properties expressed in the RDF data that match the given subject.
572 *
573 * \param subject Subject to be searched
574 * \retval array List of properties
575 * \retval boolean false: the subject was not found
576 *
577 * If a subject is not provided, all properties expressed in the RDF data are returned.
578 */
579 public function getProperties( $subject = Null) {
580
581 $aTriplesResult = $this->_filterTriples( $subject, Null, Null,
582 $debugmessage_filterresult);
583
584 // build result
585 $aresult = false;
586 foreach ($aTriplesResult as $aTriple) {
587 $aresult[]= $this->_shrink( $aTriple[ 'p']);
588 }
589
590 // make result entries unique
591 if ($aresult !== false)
592 $aresult = array_values( array_unique( $aresult));
593
594 // build debug message
595 if (!$this->_calledFromOwnCode()) {
596 if (!$aresult) {
597 if ( $subject = Null)
598 $debugmessage = "No properties found\n";
599 else
600 $debugmessage = "No properties found for subject: $subject\n";
601 }
602 else {
603
604 $debugmessage = count( $aresult) . " properties found for: $subject\n";
605 foreach( $aresult as $result) {
606 $debugmessage .= "$result\n";
607 }
608 }
609 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
610 self::debugcontext);
611
612 } // if (!$this->_calledFromOwnCode())
613
614 return $aresult;
615
616
617 } // public function getProperties
618
619 // --------------------------------------------------------
620
621 /**
622 * Gets an associative list of unique properties with their values
623 * expressed in the RDF data that match the given subject.
624 *
625 * \param subject Subject to be searched
626 * \retval array Associative list of unqique properties and their values
627 * \retval boolean false: the subject could not be found
628 *
629 * If a subject isn't provided, all unique properties expressed in the RDF data are returned.
630 *
631 * \note
632 * - All non-unique properties are \c NOT returned !
633 * - This method is a library specific extension to the RDF API and RDFa API
634 */
635 public function _getUniqueProperties( $subject = Null) {
636
637 $aTriplesResult = $this->_filterTriples( $subject, Null, Null,
638 $debugmessage_filterresult);
639
640 // build result
641 $aresult = false;
642 $afound = array();
643 foreach ($aTriplesResult as $pos => $aTriple) {
644 // isolate predicate and check if it was already found
645 $thispredicate = $this->_shrink( $aTriple[ 'p']);
646 if (isset( $afound[ $thispredicate])) {
647 unset( $aresult[ $thispredicate]);
648 continue;
649 } else {
650 $afound[ $thispredicate] = true;
651 $aresult[ $thispredicate] = $this->_shrink( $aTriple[ 'o']);
652 }
653 }
654
655 // build debug message
656 if (!$this->_calledFromOwnCode()) {
657 if (!$aresult) {
658 if ( $subject = Null)
659 $debugmessage = "No unique properties found\n";
660 else
661 $debugmessage = "No unique properties found for subject: $subject\n";
662 }
663 else {
664
665 $debugmessage = count( $aresult) . " unique properties found for: $subject\n";
666 foreach( $aresult as $result) {
667 $debugmessage .= "$result\n";
668 }
669 }
670 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
671 self::debugcontext);
672
673 } // if (!$this->_calledFromOwnCode())
674
675 return $aresult;
676
677
678 } // public function _getUniqueProperties
679
680 // --------------------------------------------------------
681
682 /**
683 * Retrieves a list of all values expressed in the RDF data that match the given subject and property.
684 *
685 * \param subject Subject to be searched
686 * \param property Property to be searched
687 * \retval array List of values
688 * \retval boolean false: a matching subject was not found
689 *
690 * If no arguments are provided, all values expressed in the RDF data are returned.
691 */
692 public function getValues( $subject = Null, $property = Null) {
693
694 $predicate = $property;
695 $aTriplesResult = $this->_filterTriples( $subject, $predicate, Null,
696 $debugmessage_filterresult);
697
698 // build result
699 $aresult = false;
700 foreach ($aTriplesResult as $aTriple) {
701 $aresult[]= $this->_shrink( $aTriple[ 'o']);
702 }
703
704 // make result entries unique
705 if ($aresult !== false)
706 $aresult = array_values( array_unique( $aresult));
707
708 // build debug message
709 if (!$this->_calledFromOwnCode()) {
710 $formattedTriple = $this->_debug_formatTripleFromParms( $subject, $predicate, Null);
711 if ($aresult === false) {
712 if ( $subject = Null)
713 $debugmessage = "No values found\n";
714 else
715 $debugmessage = "No values found for subject: $formattedTriple\n";
716 }
717 else {
718
719 $debugmessage = count( $aresult) . " values found for: $formattedTriple\n";
720 foreach( $aresult as $result) {
721 $debugmessage .= "$result\n";
722 }
723 }
724 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
725 self::debugcontext);
726
727 } // if (!$this->_calledFromOwnCode())
728
729 return $aresult;
730
731 } // public function getValues
732
733 // --------------------------------------------------------
734
735 /**
736 * Retrieves the first available value expressed in the RDF data that matches the given subject and property.
737 *
738 * \param subject Subject to be searched
739 * \param property Property to be searched
740 * \retval string First value of the property
741 * \retval boolean false: the subject could not be found
742 *
743 * If no arguments are provided, the first value expressed in the RDF data is returned.
744 *
745 * \note This method is a library specific extension to the RDF API and RDFa API
746 */
747 public function _getFirstValue( $subject = Null, $property = Null) {
748
749 $predicate = $property;
750 $aTriplesResult = $this->_filterTriples( $subject, $predicate, Null,
751 $debugmessage_filterresult);
752
753 // build result
754 $result = false;
755 foreach ($aTriplesResult as $aTriple) {
756 $result = $this->_shrink( $aTriple[ 'o']);
757 break;
758 }
759
760 // build debug message
761 if (!$this->_calledFromOwnCode()) {
762 $formattedTriple = $this->_debug_formatTripleFromParms( $subject, $predicate, Null);
763 if (!$result) {
764 if ($subject == Null)
765 $debugmessage = "No value found\n";
766 else
767 $debugmessage = "No value found for: $formattedTriple\n";
768 }
769 else {
770 $debugmessage = "Value $result found for: $formattedTriple\n";
771 $triplecount = count( $aTriplesResult);
772 if ($triplecount == 1)
773 $debugmessage .= "One value available";
774 else
775 $debugmessage .= "First of $triplecount values available";
776 }
777 $this->debugger->sendMessage( "$debugmessage\n$debugmessage_filterresult",
778 self::debugcontext);
779
780 } // if (!$this->_calledFromOwnCode())
781
782 return $result;
783
784 } // public function _getFirstValue
785
786 // --------------------------------------------------------
787
788 /**
789 * Sets a property value for a subject.
790 *
791 * \param subject Subject to get the property set
792 * \param property Property to be added
793 * \param value Value to be set for the property
794 * \param type The type of the value, either 'uri', 'literal' or 'bnode'
795 * (case-insensitive). Specifying the first character is sufficient.
796 * If not specified, strings starting with 'http://' are taken as a URI,
797 * otherwise as a literal
798 * \retval boolean true: property value set \n
799 * false: subject not found or invalid value type specified
800 *
801 * \see rdfa::Projection::set
802 *
803 * \note This method is a library specific extension to the RDF API and RDFa API
804 */
805
806 public function _setValue( $subject, $property, $value, $type = NULL) {
807
808 $predicate = $property;
809 $object = $value;
810
811 // insert code here
812
813 return $result;
814
815 } // public function _setValue
816
817 /**@} */ /***************** DOXYGEN GROUP ENDS - Basic APIs */
818
819 // --------------------------------------------------------
820
821 /**
822 * \name Projection API
823 */
824 /**@{ */ /***************** DOXYGEN GROUP START - Projection APIs */
825
826 /**
827 * Retrieves a single Projection given a subject and an optional template.
828 * A template can be provided for the purpose of building the Projection in an application-specific way.
829 *
830 * \param subject Subject to be searched
831 * \param template Associative array( URI/CURIE => membername) as a template to be applied to the projection object
832 * \retval rdfa::Projection The projection on the subject
833 * \retval boolean false: the subject was not found
834 *
835 */
836 public function getProjection( $subject, $template = Null) {
837
838 if ($subject == Null)
839 return false;
840
841 if ((!$template == Null) && (!is_array( $template))) {
842 $this->debugger->sendError( "Invalid type specified as template (must be array) " . get_class() ."::getProjection", self::debugcontext);
843 return false;
844 }
845
846 $fLogMessages = (!$this->_calledFromOwnCode());
847 if (! $this->_subjectExists( $subject)) {
848echo "### no subject \n";
849 if ($fLogMessages) $this->debugger->sendMessage( "Cannot get projection for subject: $subject",
850 self::debugcontext);
851 $result = false;
852 } else {
853 if ($fLogMessages) $this->debugger->sendMessage( "Get projection for subject: $subject",
854 self::debugcontext);
855 $result = new \rdfa\Projection( $this, $subject, $template);
856 }
857
858 return $result;
859
860 } // public function getProjection
861
862 // --------------------------------------------------------
863
864 /**
865 * Retrieves a list of Projections given an optional property and value to match against.
866 * A template can be provided for the purpose of building the Projection in an application-specific way.
867 *
868 * \param property Property that the subject of the projections should be linked with
869 * \param value Value that the specified property should have
870 * \param template Associative array( URI/CURIE => membername) as a template to be applied to the projection object
871 * \retval array List of rdfa::Projection as projections on the matching subjects
872 * \retval boolean false: a matching subject was not found
873 *
874 * If no arguments are provided, projections are created for all subjects from within the RDF data.
875 */
876 public function getProjections( $property = Null, $value = Null, $template = Null) {
877
878 if ((!$template == Null) && (!is_array( $template))) {
879 $this->debugger->sendError( "Invalid type specified as template (must be array) for " . get_class() ."::getProjections", self::debugcontext);
880 return false;
881 }
882
883 // providing log output about call
884 $predicate = $property;
885 $object = $value;
886 $fLogMessages = (!$this->_calledFromOwnCode());
887 $formattedTriple = $this->_debug_formatTripleFromParms( Null, $predicate, $object);
888 if ($formattedTriple != '')
889 $formattedTriple = " for: $formattedTriple";
890
891 $asubjects = $this->getSubjects( $property, $value);
892 if ($asubjects == false) {
893 if ($fLogMessages) $this->debugger->sendMessage( "Cannot get projections $formattedTriple",
894 self::debugcontext);
895 $aprojection = false;
896 } else {
897 $count = count( $asubjects);
898 if ($fLogMessages) $this->debugger->sendMessage( "Getting $count projections $formattedTriple",
899 self::debugcontext);
900 $aprojection = array();
901 foreach ($asubjects as $subject) {
902 $aprojection[] = new \rdfa\Projection( $this, $subject, $template);
903 }
904 }
905
906 return $aprojection;
907
908 } // public function getProjection
909
910 // --------------------------------------------------------
911
912 /**
913 * Retrieves a list of Projections based on a set of selection criteria.
914 * A template can be provided for the purpose of building the Projection in an application-specific way.
915 *
916 * \param query An associative array( URI/CURIE => value) specifying a multiple property filter
917 * \param template An associative array( URI/CURIE => membername) as a template to be applied to the projection object
918 * \retval array List of rdfa::Projection as projections on the matching subjects
919 * \retval boolean false: a matching subject was not found
920 *
921 * If no arguments are provided, projections are created for all subjects from within the RDF data.
922 */
923 public function query( $query, $template = Null) {
924
925 if ((!$query == Null) && (!is_array( $query))) {
926 $this->debugger->sendError( "Invalid type specified as query (must be array) for " . get_class() ."::query", self::debugcontext);
927 return false;
928 }
929 if (count( $query) == 0) {
930 $this->debugger->sendError( "Empty query array specified " . get_class() ."::query", self::debugcontext);
931 return false;
932 }
933
934 if ((!$template == Null) && (!is_array( $template))) {
935 $this->debugger->sendError( "Invalid type specified as template (must be array) " . get_class() ."::query", self::debugcontext);
936 return false;
937 }
938
939 // providing log output about query
940 $fLogMessages = (!$this->_calledFromOwnCode());
941 $debugmessage = "Querying for projections\n";
942 foreach ($query as $property => $value) {
943 $debugmessage .= "filter: $property $value\n";
944 }
945 if ($fLogMessages) $this->debugger->sendMessage( "$debugmessage",
946 self::debugcontext);
947
948 // do initial search
949 list( $property, $value) = each( $query);
950 $asubjects = $this->getSubjects( $property, $value);
951 if ($asubjects == false)
952 return false;
953
954 // create projections for examination
955 $aprojection_test = array();
956 $count = count( $asubjects);
957 if ($fLogMessages) $this->debugger->sendMessage( "Getting $count projections for filter test",
958 self::debugcontext);
959 foreach ($asubjects as $subject) {
960 $aprojection_test[] = new \rdfa\Projection( $this, $subject, $template);
961 $debugmessage .= "$subject\n";
962 }
963
964 // determine which projections have to be filtered out
965 $aFilteredSubjects = array();
966 foreach ($aprojection_test as $projection) {
967 $subject = $projection->getSubject();
968 foreach ($query as $property => $value) {
969 $avalues = $projection->getAll( $property);
970 if ($avalues == false) {
971 // filter this projection: property not found
972 $aFilteredSubjects[ $subject] = "Property $property not found";
973 break;
974 } else {
975 if (array_search( $value, $avalues, true) === false) {
976 // filter this projection: specific value not found
977 $aFilteredSubjects[ $subject] = "Property $property does not have value: $value";
978 break;
979 }
980 }
981 }
982 }
983 $count = count( $aFilteredSubjects);
984 if ($count == 0) {
985 $debugmessage = "No projections filtered\n";
986 } else {
987 $debugmessage = "Filtering $count projections\n";
988 foreach ( $aFilteredSubjects as $subject => $reason) {
989 $debugmessage .= "$subject: $reason\n";
990 }
991 }
992
993 if ($fLogMessages) $this->debugger->sendMessage( "$debugmessage",
994 self::debugcontext);
995
996 // take over unfiltered projections
997 $aprojection = array();
998 foreach ($aprojection_test as $projection) {
999 if (array_key_exists( $projection->getSubject(), $aFilteredSubjects) === false) {
1000 $aprojection[] = $projection;
1001 } else {
1002 unset( $projection);
1003 }
1004 }
1005
1006 // create log output
1007 $count = count( $aprojection);
1008 $debugmessage = "Returning $count projections \n";
1009 foreach ($aprojection as $projection) {
1010 $debugmessage .= "{$projection->getSubject()}\n";
1011 }
1012 if ($fLogMessages) $this->debugger->sendMessage( "$debugmessage",
1013 self::debugcontext);
1014 return $aprojection;
1015
1016 } // public function query
1017
1018 /**@} */ /***************** DOXYGEN GROUP ENDS - Projection APIs */
1019
1020 /**
1021 * Returns a serialization of the triple data.
1022 *
1023 * \param type Supported RDF serialization MIME Media Types according to http://www.iana.org/assignments/media-types/index.html
1024 * \retval string Serialization of the graph data
1025 * \retval boolean false: the serialization type is invalid
1026 *
1027 * Currently supported mime type identifiers are:
1028 *
1029 * - application/rdf+xml
1030 * - application/rdfxml
1031 * - text/turtle
1032 * - application/x-turtle
1033 * - text/n3
1034 * - application/json
1035 *
1036 * In addition to those, the internal type identifiers of this library can be used as well:
1037 * - rdfxml
1038 * - turtle
1039 * - n3
1040 * - json
1041 *
1042 * \note This method is a library specific extension to the RDF API and RDFa API
1043 */
1044 public function _serialize( $type ) {
1045 // set the supported types and shortcut them to the ones we use in there
1046 $validTypes = array( 'application/rdf+xml' => 'rdfxml' ,
1047 'application/rdfxml' => 'rdfxml',
1048 'text/turtle' => 'turtle',
1049 'application/x-turtle' => 'turtle',
1050 'text/n3' => 'n3',
1051 'application/json' => 'json');
1052
1053 // check if explicit mime type is specified
1054 if (isset( $validTypes[ $type])) {
1055 $type = $validTypes[ $type];
1056 } else {
1057 // check if internal type is given
1058 $internalTypes = array_unique( array_flip( $validTypes));
1059 if (!isset( $internalTypes[ $type]))
1060 return false;
1061 }
1062
1063 switch ($type) {
1064
1065 case 'rdfxml':
1066 $ser = \ARC2::getRDFXMLSerializer();
1067 break;
1068
1069 case 'turtle':
1070 $ser = \ARC2::getTurtleSerializer();
1071 break;
1072
1073 case 'n3':
1074 $ser = \ARC2::getNTriplesSerializer();
1075 break;
1076
1077 case 'json':
1078 $ser = \ARC2::getRDFJSONSerializer();
1079 break;
1080
1081 } // switch ($type)
1082
1083 return $ser->getSerializedTriples( $this->aTriples);
1084
1085 } // public function _serialize
1086
1087} // class Data
1088
1089?>
Note: See TracBrowser for help on using the repository browser.