289d7dcfe9b09153c72e87388e4f0013f3bcacaf
[yaffs-website] / vendor / easyrdf / easyrdf / lib / EasyRdf / Serialiser / RdfXml.php
1 <?php
2 /**
3  * EasyRdf
4  *
5  * LICENSE
6  *
7  * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
17  *    promote products derived from this software without specific prior
18  *    written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  * @package    EasyRdf
33  * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
34  * @license    http://www.opensource.org/licenses/bsd-license.php
35  */
36
37 /**
38  * Class to serialise an EasyRdf_Graph to RDF/XML
39  * with no external dependancies.
40  *
41  * @package    EasyRdf
42  * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
43  * @license    http://www.opensource.org/licenses/bsd-license.php
44  */
45 class EasyRdf_Serialiser_RdfXml extends EasyRdf_Serialiser
46 {
47     private $outputtedResources = array();
48
49     /** A constant for the RDF Type property URI */
50     const RDF_XML_LITERAL = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral';
51
52     /**
53      * Protected method to serialise an object node into an XML object
54      * @ignore
55      */
56     protected function rdfxmlObject($property, $obj, $depth)
57     {
58         $indent = str_repeat('  ', $depth);
59
60         if ($property[0] === ':') {
61             $property = substr($property, 1);
62         }
63
64         if (is_object($obj) and $obj instanceof EasyRdf_Resource) {
65             $pcount = count($obj->propertyUris());
66             $rpcount = $this->reversePropertyCount($obj);
67             $alreadyOutput = isset($this->outputtedResources[$obj->getUri()]);
68
69             $tag = "{$indent}<{$property}";
70             if ($obj->isBNode()) {
71                 if ($alreadyOutput or $rpcount > 1 or $pcount == 0) {
72                     $tag .= " rdf:nodeID=\"".htmlspecialchars($obj->getBNodeId()).'"';
73                 }
74             } else {
75                 if ($alreadyOutput or $rpcount != 1 or $pcount == 0) {
76                     $tag .= " rdf:resource=\"".htmlspecialchars($obj->getURI()).'"';
77                 }
78             }
79
80             if ($alreadyOutput == false and $rpcount == 1 and $pcount > 0) {
81                 $xml = $this->rdfxmlResource($obj, false, $depth+1);
82                 if ($xml) {
83                     return "$tag>$xml$indent</$property>\n\n";
84                 } else {
85                     return '';
86                 }
87             } else {
88                 return $tag."/>\n";
89             }
90
91         } elseif (is_object($obj) and $obj instanceof EasyRdf_Literal) {
92             $atrributes = "";
93             $datatype = $obj->getDatatypeUri();
94             if ($datatype) {
95                 if ($datatype == self::RDF_XML_LITERAL) {
96                     $atrributes .= " rdf:parseType=\"Literal\"";
97                     $value = strval($obj);
98                 } else {
99                     $datatype = htmlspecialchars($datatype);
100                     $atrributes .= " rdf:datatype=\"$datatype\"";
101                 }
102             } elseif ($obj->getLang()) {
103                 $atrributes .= ' xml:lang="'.
104                                htmlspecialchars($obj->getLang()).'"';
105             }
106
107             // Escape the value
108             if (!isset($value)) {
109                 $value = htmlspecialchars(strval($obj));
110             }
111
112             return "{$indent}<{$property}{$atrributes}>{$value}</{$property}>\n";
113         } else {
114             throw new EasyRdf_Exception(
115                 "Unable to serialise object to xml: ".getType($obj)
116             );
117         }
118     }
119
120     /**
121      * Protected method to serialise a whole resource and its properties
122      * @ignore
123      */
124     protected function rdfxmlResource($res, $showNodeId, $depth = 1)
125     {
126         // Keep track of the resources we have already serialised
127         if (isset($this->outputtedResources[$res->getUri()])) {
128             return '';
129         } else {
130             $this->outputtedResources[$res->getUri()] = true;
131         }
132
133         // If the resource has no properties - don't serialise it
134         $properties = $res->propertyUris();
135         if (count($properties) == 0) {
136             return '';
137         }
138
139         $type = $res->type();
140         if ($type) {
141             $this->addPrefix($type);
142         } else {
143             $type = 'rdf:Description';
144         }
145
146         $indent = str_repeat('  ', $depth);
147         $xml = "\n$indent<$type";
148         if ($res->isBNode()) {
149             if ($showNodeId) {
150                 $xml .= ' rdf:nodeID="'.htmlspecialchars($res->getBNodeId()).'"';
151             }
152         } else {
153             $xml .= ' rdf:about="'.htmlspecialchars($res->getUri()).'"';
154         }
155         $xml .= ">\n";
156
157         if ($res instanceof EasyRdf_Container) {
158             foreach ($res as $item) {
159                 $xml .= $this->rdfxmlObject('rdf:li', $item, $depth+1);
160             }
161         } else {
162             foreach ($properties as $property) {
163                 $short = EasyRdf_Namespace::shorten($property, true);
164                 if ($short) {
165                     $this->addPrefix($short);
166                     $objects = $res->all("<$property>");
167                     if ($short == 'rdf:type' && $type != 'rdf:Description') {
168                         array_shift($objects);
169                     }
170                     foreach ($objects as $object) {
171                         $xml .= $this->rdfxmlObject($short, $object, $depth+1);
172                     }
173                 } else {
174                     throw new EasyRdf_Exception(
175                         "It is not possible to serialse the property ".
176                         "'$property' to RDF/XML."
177                     );
178                 }
179             }
180         }
181         $xml .= "$indent</$type>\n";
182
183         return $xml;
184     }
185
186
187     /**
188      * Method to serialise an EasyRdf_Graph to RDF/XML
189      *
190      * @param EasyRdf_Graph $graph   An EasyRdf_Graph object.
191      * @param string        $format  The name of the format to convert to.
192      * @param array         $options
193      * @throws EasyRdf_Exception
194      * @return string The RDF in the new desired format.
195      */
196     public function serialise($graph, $format, array $options = array())
197     {
198         parent::checkSerialiseParams($graph, $format);
199
200         if ($format != 'rdfxml') {
201             throw new EasyRdf_Exception(
202                 "EasyRdf_Serialiser_RdfXml does not support: $format"
203             );
204         }
205
206         // store of namespaces to be appended to the rdf:RDF tag
207         $this->prefixes = array('rdf' => true);
208
209         // store of the resource URIs we have serialised
210         $this->outputtedResources = array();
211
212         $xml = '';
213
214         // Serialise URIs first
215         foreach ($graph->resources() as $resource) {
216             if (!$resource->isBnode()) {
217                 $xml .= $this->rdfxmlResource($resource, true);
218             }
219         }
220
221         // Serialise bnodes afterwards
222         foreach ($graph->resources() as $resource) {
223             if ($resource->isBnode()) {
224                 $xml .= $this->rdfxmlResource($resource, true);
225             }
226         }
227
228         // iterate through namepsaces array prefix and output a string.
229         $namespaceStr = '';
230         foreach ($this->prefixes as $prefix => $count) {
231             $url = EasyRdf_Namespace::get($prefix);
232
233             if (strlen($namespaceStr)) {
234                 $namespaceStr .= "\n        ";
235             }
236
237             if (strlen($prefix) === 0) {
238                 $namespaceStr .= ' xmlns="'.htmlspecialchars($url).'"';
239             } else {
240                 $namespaceStr .= ' xmlns:'.$prefix.'="'.htmlspecialchars($url).'"';
241             }
242         }
243
244         return "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
245                "<rdf:RDF". $namespaceStr . ">\n" . $xml . "\n</rdf:RDF>\n";
246     }
247 }