Minor dependency updates
[yaffs-website] / vendor / easyrdf / easyrdf / lib / EasyRdf / Serialiser / Turtle.php
1 <?php
2
3 /**
4  * EasyRdf
5  *
6  * LICENSE
7  *
8  * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  *    this list of conditions and the following disclaimer in the documentation
16  *    and/or other materials provided with the distribution.
17  * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
18  *    promote products derived from this software without specific prior
19  *    written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * @package    EasyRdf
34  * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
35  * @license    http://www.opensource.org/licenses/bsd-license.php
36  */
37
38 /**
39  * Class to serialise an EasyRdf_Graph to Turtle
40  * with no external dependancies.
41  *
42  * http://www.w3.org/TR/turtle/
43  *
44  * @package    EasyRdf
45  * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
46  * @license    http://www.opensource.org/licenses/bsd-license.php
47  */
48 class EasyRdf_Serialiser_Turtle extends EasyRdf_Serialiser
49 {
50     private $outputtedBnodes = array();
51
52     /**
53      * Given a IRI string, escape and enclose in angle brackets.
54      *
55      * @param  string $resourceIri
56      * @return string
57      */
58     public static function escapeIri($resourceIri)
59     {
60         $escapedIri = str_replace('>', '\\>', $resourceIri);
61         return "<$escapedIri>";
62     }
63
64     /**
65      * Given a string, enclose in quotes and escape any quotes in the string.
66      * Strings containing tabs, linefeeds or carriage returns will be
67      * enclosed in three double quotes (""").
68      *
69      * @param  string $value
70      * @return string
71      */
72     public static function quotedString($value)
73     {
74         if (preg_match('/[\t\n\r]/', $value)) {
75             $escaped = str_replace(array('\\', '"""'), array('\\\\', '\\"""'), $value);
76             return '"""'.$escaped.'"""';
77         } else {
78             $escaped = str_replace(array('\\', '"'), array('\\\\', '\\"'), $value);
79             return '"'.$escaped.'"';
80         }
81     }
82
83     /**
84      * Given a an EasyRdf_Resource or URI, convert it into a string, suitable to
85      * be written to a Turtle document. URIs will be shortened into CURIES
86      * where possible.
87      *
88      * @param  EasyRdf_Resource $resource   The resource to convert to a Turtle string
89      * @param  boolean $createNamespace     If true, a new namespace may be created
90      * @return string
91      */
92     public function serialiseResource($resource, $createNamespace = false)
93     {
94         if (is_object($resource)) {
95             if ($resource->isBNode()) {
96                 return $resource->getUri();
97             }
98
99             $resource = $resource->getUri();
100         }
101
102         $short = EasyRdf_Namespace::shorten($resource, $createNamespace);
103
104         if ($short) {
105             $this->addPrefix($short);
106             return $short;
107         }
108
109         return self::escapeIri($resource);
110     }
111
112     /**
113      * Given an EasyRdf_Literal object, convert it into a string, suitable to
114      * be written to a Turtle document. Supports multiline literals and literals with
115      * datatypes or languages.
116      *
117      * @param  EasyRdf_Literal $literal
118      * @return string
119      */
120     public function serialiseLiteral($literal)
121     {
122         $value = strval($literal);
123         $quoted = self::quotedString($value);
124
125         if ($datatype = $literal->getDatatypeUri()) {
126             if ($datatype == 'http://www.w3.org/2001/XMLSchema#integer') {
127                 return sprintf('%d', $value);
128             } elseif ($datatype == 'http://www.w3.org/2001/XMLSchema#decimal') {
129                 return sprintf('%s', $value);
130             } elseif ($datatype == 'http://www.w3.org/2001/XMLSchema#double') {
131                 return sprintf('%e', $value);
132             } elseif ($datatype == 'http://www.w3.org/2001/XMLSchema#boolean') {
133                 return sprintf('%s', $value);
134             } else {
135                 $escaped = $this->serialiseResource($datatype, true);
136                 return sprintf('%s^^%s', $quoted, $escaped);
137             }
138         } elseif ($lang = $literal->getLang()) {
139             return $quoted . '@' . $lang;
140         } else {
141             return $quoted;
142         }
143     }
144
145     /**
146      * Convert an EasyRdf object into a string suitable to
147      * be written to a Turtle document.
148      *
149      * @param  EasyRdf_Resource|EasyRdf_Literal $object
150      * @return string
151      */
152     public function serialiseObject($object)
153     {
154         if ($object instanceof EasyRdf_Resource) {
155             return $this->serialiseResource($object);
156         } elseif ($object instanceof EasyRdf_Literal) {
157             return $this->serialiseLiteral($object);
158         } else {
159             throw new InvalidArgumentException(
160                 "serialiseObject() requires \$object to be ".
161                 "of type EasyRdf_Resource or EasyRdf_Literal"
162             );
163         }
164     }
165
166
167     /**
168      * Protected method to serialise a RDF collection
169      * @ignore
170      */
171     protected function serialiseCollection($node, $indent)
172     {
173         $turtle = '(';
174         $count = 0;
175         while ($node) {
176             if ($id = $node->getBNodeId()) {
177                 $this->outputtedBnodes[$id] = true;
178             }
179
180             $value = $node->get('rdf:first');
181             $node = $node->get('rdf:rest');
182             if ($node and $node->hasProperty('rdf:first')) {
183                 $count++;
184             }
185
186             if ($value !== null) {
187                 $serialised = $this->serialiseObject($value);
188                 if ($count) {
189                     $turtle .= "\n$indent  $serialised";
190                 } else {
191                     $turtle .= " ".$serialised;
192                 }
193             }
194         }
195         if ($count) {
196             $turtle .= "\n$indent)";
197         } else {
198             $turtle .= " )";
199         }
200         return $turtle;
201     }
202
203     /**
204      * Protected method to serialise the properties of a resource
205      * @ignore
206      */
207     protected function serialiseProperties($res, $depth = 1)
208     {
209         $properties = $res->propertyUris();
210         $indent = str_repeat(' ', ($depth*2)-1);
211
212         $turtle = '';
213         if (count($properties) > 1) {
214             $turtle .= "\n$indent";
215         }
216
217         $pCount = 0;
218         foreach ($properties as $property) {
219             if ($property === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type') {
220                 $pStr = 'a';
221             } else {
222                 $pStr = $this->serialiseResource($property, true);
223             }
224
225             if ($pCount) {
226                 $turtle .= " ;\n$indent";
227             }
228
229             $turtle .= ' ' . $pStr;
230
231             $oCount = 0;
232             foreach ($res->all("<$property>") as $object) {
233                 if ($oCount) {
234                     $turtle .= ',';
235                 }
236
237                 if ($object instanceof EasyRdf_Collection) {
238                     $turtle .= ' ' . $this->serialiseCollection($object, $indent);
239                 } elseif ($object instanceof EasyRdf_Resource and $object->isBNode()) {
240                     $id = $object->getBNodeId();
241                     $rpcount = $this->reversePropertyCount($object);
242                     if ($rpcount <= 1 and !isset($this->outputtedBnodes[$id])) {
243                         // Nested unlabelled Blank Node
244                         $this->outputtedBnodes[$id] = true;
245                         $turtle .= ' [';
246                         $turtle .= $this->serialiseProperties($object, $depth+1);
247                         $turtle .= ' ]';
248                     } else {
249                         // Multiple properties pointing to this blank node
250                         $turtle .= ' ' . $this->serialiseObject($object);
251                     }
252                 } else {
253                     $turtle .= ' ' . $this->serialiseObject($object);
254                 }
255                 $oCount++;
256             }
257             $pCount++;
258         }
259
260         if ($depth == 1) {
261             $turtle .= " .";
262             if ($pCount > 1) {
263                 $turtle .= "\n";
264             }
265         } elseif ($pCount > 1) {
266             $turtle .= "\n" . str_repeat(' ', (($depth-1)*2)-1);
267         }
268
269         return $turtle;
270     }
271
272     /**
273      * @ignore
274      */
275     protected function serialisePrefixes()
276     {
277         $turtle = '';
278         foreach ($this->prefixes as $prefix => $count) {
279             $url = EasyRdf_Namespace::get($prefix);
280             $turtle .= "@prefix $prefix: <$url> .\n";
281         }
282         return $turtle;
283     }
284
285     /**
286      * @ignore
287      */
288     protected function serialiseSubjects(EasyRdf_Graph $graph, $filterType)
289     {
290         $turtle = '';
291         foreach ($graph->resources() as $resource) {
292             /** @var $resource EasyRdf_Resource */
293             // If the resource has no properties - don't serialise it
294             $properties = $resource->propertyUris();
295             if (count($properties) == 0) {
296                 continue;
297             }
298
299             // Is this node of the right type?
300             $thisType = $resource->isBNode() ? 'bnode' : 'uri';
301             if ($thisType != $filterType) {
302                 continue;
303             }
304
305             if ($thisType == 'bnode') {
306                 $id = $resource->getBNodeId();
307
308                 if (isset($this->outputtedBnodes[$id])) {
309                     // Already been serialised
310                     continue;
311                 }
312
313                 $this->outputtedBnodes[$id] = true;
314                 $rpcount = $this->reversePropertyCount($resource);
315
316                 if ($rpcount == 0) {
317                     $turtle .= '[]';
318                 } else {
319                     $turtle .= $this->serialiseResource($resource);
320                 }
321             } else {
322                 $turtle .= $this->serialiseResource($resource);
323             }
324
325             $turtle .= $this->serialiseProperties($resource);
326             $turtle .= "\n";
327         }
328         return $turtle;
329     }
330
331     /**
332      * Serialise an EasyRdf_Graph to Turtle.
333      *
334      * @param EasyRdf_Graph $graph   An EasyRdf_Graph object.
335      * @param string        $format  The name of the format to convert to.
336      * @param array         $options
337      * @throws EasyRdf_Exception
338      * @return string The RDF in the new desired format.
339      */
340     public function serialise($graph, $format, array $options = array())
341     {
342         parent::checkSerialiseParams($graph, $format);
343
344         if ($format != 'turtle' and $format != 'n3') {
345             throw new EasyRdf_Exception(
346                 "EasyRdf_Serialiser_Turtle does not support: $format"
347             );
348         }
349
350         $this->prefixes = array();
351         $this->outputtedBnodes = array();
352
353         $turtle = '';
354         $turtle .= $this->serialiseSubjects($graph, 'uri');
355         $turtle .= $this->serialiseSubjects($graph, 'bnode');
356
357         if (count($this->prefixes)) {
358             return $this->serialisePrefixes() . "\n" . $turtle;
359         } else {
360             return $turtle;
361         }
362     }
363 }