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

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

rdfint

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