8 * Copyright (c) 2009-2013 Nicholas J Humfrey. All rights reserved.
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
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.
34 * @copyright Copyright (c) 2009-2013 Nicholas J Humfrey
35 * @license http://www.opensource.org/licenses/bsd-license.php
39 * Class that represents an RDF Literal
42 * @copyright Copyright (c) 2009-2013 Nicholas J Humfrey
43 * @license http://www.opensource.org/licenses/bsd-license.php
47 /** @ignore a mapping from datatype uri to class name */
48 private static $datatypeMap = array();
50 /** @ignore A mapping from class name to datatype URI */
51 private static $classMap = array();
53 /** @ignore The string value for this literal */
54 protected $value = null;
56 /** @ignore The language of the literal (e.g. 'en') */
57 protected $lang = null;
59 /** @ignore The datatype URI of the literal */
60 protected $datatype = null;
63 /** Create a new literal object
65 * PHP values of type bool, int or float, will automatically be converted
66 * to the corresponding datatype and PHP sub-class.
68 * If a registered datatype is given, then the registered subclass of EasyRdf_Literal
71 * Note that literals are not required to have a language or datatype.
72 * Literals cannot have both a language and a datatype.
74 * @param mixed $value The value of the literal or an associative array
75 * @param string $lang The natural language of the literal or null (e.g. 'en')
76 * @param string $datatype The datatype of the literal or null (e.g. 'xsd:integer')
77 * @return object EasyRdf_Literal (or subclass of EasyRdf_Literal)
79 public static function create($value, $lang = null, $datatype = null)
81 if (EasyRdf_Utils::isAssociativeArray($value)) {
82 if (isset($value['xml:lang'])) {
83 $lang = $value['xml:lang'];
84 } elseif (isset($value['lang'])) {
85 $lang = $value['lang'];
87 if (isset($value['datatype'])) {
88 $datatype = $value['datatype'];
90 $value = isset($value['value']) ? $value['value'] : null;
93 if (is_null($datatype) or $datatype === '') {
94 if (is_null($lang) or $lang === '') {
95 // Automatic datatype selection
96 $datatype = self::getDatatypeForValue($value);
98 } elseif (is_object($datatype)) {
99 $datatype = strval($datatype);
101 // Expand shortened URIs (qnames)
102 $datatype = EasyRdf_Namespace::expand($datatype);
105 // Work out what class to use for this datatype
106 if (isset(self::$datatypeMap[$datatype])) {
107 $class = self::$datatypeMap[$datatype];
109 $class = 'EasyRdf_Literal';
111 return new $class($value, $lang, $datatype);
114 /** Register an RDF datatype with a PHP class name
116 * When parsing registered class will be used whenever the datatype
119 * When serialising a registered class, the mapping will be used to
120 * set the datatype in the RDF.
123 * EasyRdf_Literal::registerDatatype('xsd:dateTime', 'My_DateTime_Class');
125 * @param string $datatype The RDF datatype (e.g. xsd:dateTime)
126 * @param string $class The PHP class name (e.g. My_DateTime_Class)
128 public static function setDatatypeMapping($datatype, $class)
130 if (!is_string($datatype) or $datatype == null or $datatype == '') {
131 throw new InvalidArgumentException(
132 "\$datatype should be a string and cannot be null or empty"
136 if (!is_string($class) or $class == null or $class == '') {
137 throw new InvalidArgumentException(
138 "\$class should be a string and cannot be null or empty"
142 $datatype = EasyRdf_Namespace::expand($datatype);
143 self::$datatypeMap[$datatype] = $class;
144 self::$classMap[$class] = $datatype;
147 /** Remove the mapping between an RDF datatype and a PHP class name
149 * @param string $datatype The RDF datatype (e.g. xsd:dateTime)
151 public static function deleteDatatypeMapping($datatype)
153 if (!is_string($datatype) or $datatype == null or $datatype == '') {
154 throw new InvalidArgumentException(
155 "\$datatype should be a string and cannot be null or empty"
159 $datatype = EasyRdf_Namespace::expand($datatype);
160 if (isset(self::$datatypeMap[$datatype])) {
161 $class = self::$datatypeMap[$datatype];
162 unset(self::$datatypeMap[$datatype]);
163 unset(self::$classMap[$class]);
167 /** Get datatype URI for a PHP value.
169 * This static function is intended for internal use.
170 * Given a PHP value, it will return an XSD datatype
171 * URI for that value, for example:
172 * http://www.w3.org/2001/XMLSchema#integer
174 * @return string A URI for the datatype of $value.
176 public static function getDatatypeForValue($value)
178 if (is_float($value)) {
179 return 'http://www.w3.org/2001/XMLSchema#double';
180 } elseif (is_int($value)) {
181 return 'http://www.w3.org/2001/XMLSchema#integer';
182 } elseif (is_bool($value)) {
183 return 'http://www.w3.org/2001/XMLSchema#boolean';
184 } elseif (is_object($value) and $value instanceof DateTime) {
185 return 'http://www.w3.org/2001/XMLSchema#dateTime';
193 /** Constructor for creating a new literal
195 * @param string $value The value of the literal
196 * @param string $lang The natural language of the literal or null (e.g. 'en')
197 * @param string $datatype The datatype of the literal or null (e.g. 'xsd:string')
198 * @return object EasyRdf_Literal
200 public function __construct($value, $lang = null, $datatype = null)
202 $this->value = $value;
203 $this->lang = $lang ? $lang : null;
204 $this->datatype = $datatype ? $datatype : null;
206 if ($this->datatype) {
207 if (is_object($this->datatype)) {
208 // Convert objects to strings
209 $this->datatype = strval($this->datatype);
211 // Expand shortened URIs (CURIEs)
212 $this->datatype = EasyRdf_Namespace::expand($this->datatype);
215 // Literals can not have both a language and a datatype
218 // Set the datatype based on the subclass
219 $class = get_class($this);
220 if (isset(self::$classMap[$class])) {
221 $this->datatype = self::$classMap[$class];
226 if (is_float($this->value)) {
227 // special handling of floats, as they suffer from locale [mis]configuration
228 $this->value = rtrim(sprintf('%F', $this->value), '0');
230 // Cast value to string
231 settype($this->value, 'string');
235 /** Returns the value of the literal.
237 * @return string Value of this literal.
239 public function getValue()
244 /** Returns the full datatype URI of the literal.
246 * @return string Datatype URI of this literal.
248 public function getDatatypeUri()
250 return $this->datatype;
253 /** Returns the shortened datatype URI of the literal.
255 * @return string Datatype of this literal (e.g. xsd:integer).
257 public function getDatatype()
259 if ($this->datatype) {
260 return EasyRdf_Namespace::shorten($this->datatype);
266 /** Returns the language of the literal.
268 * @return string Language of this literal.
270 public function getLang()
275 /** Returns the properties of the literal as an associative array
278 * array('type' => 'literal', 'value' => 'string value')
280 * @return array The properties of the literal
282 public function toRdfPhp()
286 'value' => $this->value
289 if ($this->datatype) {
290 $array['datatype'] = $this->datatype;
294 $array['lang'] = $this->lang;
300 /** Magic method to return the value of a literal as a string
302 * @return string The value of the literal
304 public function __toString()
306 return isset($this->value) ? $this->value : '';
309 /** Return pretty-print view of the literal
311 * @param string $format Either 'html' or 'text'
312 * @param string $color The colour of the text
315 public function dumpValue($format = 'html', $color = 'black')
317 return EasyRdf_Utils::dumpLiteralValue($this, $format, $color);
322 Register default set of datatype classes
325 EasyRdf_Literal::setDatatypeMapping('xsd:boolean', 'EasyRdf_Literal_Boolean');
326 EasyRdf_Literal::setDatatypeMapping('xsd:date', 'EasyRdf_Literal_Date');
327 EasyRdf_Literal::setDatatypeMapping('xsd:dateTime', 'EasyRdf_Literal_DateTime');
328 EasyRdf_Literal::setDatatypeMapping('xsd:decimal', 'EasyRdf_Literal_Decimal');
329 EasyRdf_Literal::setDatatypeMapping('xsd:hexBinary', 'EasyRdf_Literal_HexBinary');
330 EasyRdf_Literal::setDatatypeMapping('rdf:HTML', 'EasyRdf_Literal_HTML');
331 EasyRdf_Literal::setDatatypeMapping('xsd:integer', 'EasyRdf_Literal_Integer');
332 EasyRdf_Literal::setDatatypeMapping('rdf:XMLLiteral', 'EasyRdf_Literal_XML');