Minor dependency updates
[yaffs-website] / vendor / easyrdf / easyrdf / lib / EasyRdf / Namespace.php
1 <?php
2
3 /**
4  * EasyRdf
5  *
6  * LICENSE
7  *
8  * Copyright (c) 2009-2014 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-2014 Nicholas J Humfrey
35  * @license    http://www.opensource.org/licenses/bsd-license.php
36  */
37
38 /**
39  * A namespace registry and manipulation class.
40  *
41  * @package    EasyRdf
42  * @copyright  Copyright (c) 2009-2014 Nicholas J Humfrey
43  * @license    http://www.opensource.org/licenses/bsd-license.php
44  */
45 class EasyRdf_Namespace
46 {
47     /** Namespace registry
48      *
49      * List of default namespaces come from:
50      *  - http://www.w3.org/2011/rdfa-context/rdfa-1.1
51      *
52      * With a few extras added.
53      *
54      */
55     private static $initial_namespaces = array(
56         'bibo'    => 'http://purl.org/ontology/bibo/',
57         'cc'      => 'http://creativecommons.org/ns#',
58         'cert'    => 'http://www.w3.org/ns/auth/cert#',
59         'ctag'    => 'http://commontag.org/ns#',
60         'dc'      => 'http://purl.org/dc/terms/',
61         'dc11'    => 'http://purl.org/dc/elements/1.1/',
62         'dcat'    => 'http://www.w3.org/ns/dcat#',
63         'dcterms' => 'http://purl.org/dc/terms/',
64         'doap'    => 'http://usefulinc.com/ns/doap#',
65         'exif'    => 'http://www.w3.org/2003/12/exif/ns#',
66         'foaf'    => 'http://xmlns.com/foaf/0.1/',
67         'geo'     => 'http://www.w3.org/2003/01/geo/wgs84_pos#',
68         'gr'      => 'http://purl.org/goodrelations/v1#',
69         'grddl'   => 'http://www.w3.org/2003/g/data-view#',
70         'ical'    => 'http://www.w3.org/2002/12/cal/icaltzd#',
71         'ma'      => 'http://www.w3.org/ns/ma-ont#',
72         'og'      => 'http://ogp.me/ns#',
73         'org'     => 'http://www.w3.org/ns/org#',
74         'owl'     => 'http://www.w3.org/2002/07/owl#',
75         'prov'    => 'http://www.w3.org/ns/prov#',
76         'qb'      => 'http://purl.org/linked-data/cube#',
77         'rdf'     => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
78         'rdfa'    => 'http://www.w3.org/ns/rdfa#',
79         'rdfs'    => 'http://www.w3.org/2000/01/rdf-schema#',
80         'rev'     => 'http://purl.org/stuff/rev#',
81         'rif'     => 'http://www.w3.org/2007/rif#',
82         'rr'      => 'http://www.w3.org/ns/r2rml#',
83         'rss'     => 'http://purl.org/rss/1.0/',
84         'schema'  => 'http://schema.org/',
85         'sd'      => 'http://www.w3.org/ns/sparql-service-description#',
86         'sioc'    => 'http://rdfs.org/sioc/ns#',
87         'skos'    => 'http://www.w3.org/2004/02/skos/core#',
88         'skosxl'  => 'http://www.w3.org/2008/05/skos-xl#',
89         'synd'    => 'http://purl.org/rss/1.0/modules/syndication/',
90         'v'       => 'http://rdf.data-vocabulary.org/#',
91         'vcard'   => 'http://www.w3.org/2006/vcard/ns#',
92         'void'    => 'http://rdfs.org/ns/void#',
93         'wdr'     => 'http://www.w3.org/2007/05/powder#',
94         'wdrs'    => 'http://www.w3.org/2007/05/powder-s#',
95         'wot'     => 'http://xmlns.com/wot/0.1/',
96         'xhv'     => 'http://www.w3.org/1999/xhtml/vocab#',
97         'xml'     => 'http://www.w3.org/XML/1998/namespace',
98         'xsd'     => 'http://www.w3.org/2001/XMLSchema#',
99     );
100
101     private static $namespaces = null;
102
103     private static $default = null;
104
105     /** Counter for numbering anonymous namespaces */
106     private static $anonymousNamespaceCount = 0;
107
108     /**
109       * Return all the namespaces registered
110       *
111       * @return array Associative array of all the namespaces.
112       */
113     public static function namespaces()
114     {
115         if (self::$namespaces === null) {
116             self::resetNamespaces();
117         }
118
119         return self::$namespaces;
120     }
121
122     /**
123      * Resets list of namespaces to the one, which is provided by EasyRDF
124      * useful for tests, among other things
125      */
126     public static function resetNamespaces()
127     {
128         self::$namespaces = self::$initial_namespaces;
129     }
130
131     /**
132       * Return a namespace given its prefix.
133       *
134       * @param string $prefix The namespace prefix (eg 'foaf')
135       * @return string The namespace URI (eg 'http://xmlns.com/foaf/0.1/')
136       */
137     public static function get($prefix)
138     {
139         if (!is_string($prefix) or $prefix === null) {
140             throw new InvalidArgumentException(
141                 "\$prefix should be a string and cannot be null or empty"
142             );
143         }
144
145         if (preg_match('/\W/', $prefix)) {
146             throw new InvalidArgumentException(
147                 "\$prefix should only contain alpha-numeric characters"
148             );
149         }
150
151         $prefix = strtolower($prefix);
152         $namespaces = self::namespaces();
153
154         if (array_key_exists($prefix, $namespaces)) {
155             return $namespaces[$prefix];
156         } else {
157             return null;
158         }
159     }
160
161     /**
162       * Register a new namespace.
163       *
164       * @param string $prefix The namespace prefix (eg 'foaf')
165       * @param string $long The namespace URI (eg 'http://xmlns.com/foaf/0.1/')
166       */
167     public static function set($prefix, $long)
168     {
169         if (!is_string($prefix) or $prefix === null) {
170             throw new InvalidArgumentException(
171                 "\$prefix should be a string and cannot be null or empty"
172             );
173         }
174
175         if ($prefix !== '') {
176             // prefix        ::= Name minus ":"                   // see: http://www.w3.org/TR/REC-xml-names/#NT-NCName
177             // Name          ::= NameStartChar (NameChar)*        // see: http://www.w3.org/TR/REC-xml/#NT-Name
178             // NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] |
179             //                   [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] |
180             //                   [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
181             // NameChar      ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
182
183             $_name_start_char =
184                 'A-Z_a-z\xc0-\xD6\xd8-\xf6\xf8-\xff\x{0100}-\x{02ff}\x{0370}-\x{037d}' .
185                 '\x{037F}-\x{1FFF}\x{200C}-\x{200D}\x{2070}-\x{218F}\x{2C00}-\x{2FEF}\x{3001}-\x{D7FF}' .
186                 '\x{F900}-\x{FDCF}\x{FDF0}-\x{FFFD}\x{10000}-\x{EFFFF}';
187
188             $_name_char =
189                 $_name_start_char .
190                 '\-.0-9\xb7\x{0300}-\x{036f}\x{203f}-\x{2040}';
191
192             $regex = "#^[{$_name_start_char}]{1}[{$_name_char}]{0,}$#u";
193
194             $match_result = preg_match($regex, $prefix);
195
196             if ($match_result === false) {
197                 throw new LogicException('regexp error');
198             }
199
200             if ($match_result === 0) {
201                 throw new InvalidArgumentException(
202                     "\$prefix should match RDFXML-QName specification. got: {$prefix}"
203                 );
204             }
205         }
206
207         if (!is_string($long) or $long === null or $long === '') {
208             throw new InvalidArgumentException(
209                 "\$long should be a string and cannot be null or empty"
210             );
211         }
212
213         $prefix = strtolower($prefix);
214
215         $namespaces = self::namespaces();
216         $namespaces[$prefix] = $long;
217
218         self::$namespaces = $namespaces;
219     }
220
221     /**
222       * Get the default namespace
223       *
224       * Returns the URI of the default namespace or null
225       * if no default namespace is defined.
226       *
227       * @return string The URI of the default namespace
228       */
229     public static function getDefault()
230     {
231         return self::$default;
232     }
233
234     /**
235       * Set the default namespace
236       *
237       * Set the default namespace to either a URI or the prefix of
238       * an already defined namespace.
239       *
240       * Example:
241       *   EasyRdf_Namespace::setDefault('http://schema.org/');
242       *
243       * @param string $namespace The URI or prefix of a namespace (eg 'og')
244       */
245     public static function setDefault($namespace)
246     {
247         if (is_null($namespace) or $namespace === '') {
248             self::$default = null;
249         } elseif (preg_match('/^\w+$/', $namespace)) {
250             $namespaces = self::namespaces();
251
252             if (!isset($namespaces[$namespace])) {
253                 throw new InvalidArgumentException(
254                     "Unable to set default namespace to unknown prefix: $namespace"
255                 );
256             }
257
258             self::$default = $namespaces[$namespace];
259         } else {
260             self::$default = $namespace;
261         }
262     }
263
264     /**
265       * Delete an existing namespace.
266       *
267       * @param string $prefix The namespace prefix (eg 'foaf')
268       */
269     public static function delete($prefix)
270     {
271         if (!is_string($prefix) or $prefix === null or $prefix === '') {
272             throw new InvalidArgumentException(
273                 "\$prefix should be a string and cannot be null or empty"
274             );
275         }
276
277         $prefix = strtolower($prefix);
278         self::namespaces();  // make sure, that self::$namespaces is initialized
279         if (isset(self::$namespaces[$prefix])) {
280             unset(self::$namespaces[$prefix]);
281         }
282     }
283
284     /**
285       * Delete the anonymous namespaces and reset the counter to 0
286       */
287     public static function reset()
288     {
289         while (self::$anonymousNamespaceCount > 0) {
290             self::delete('ns'.(self::$anonymousNamespaceCount-1));
291             self::$anonymousNamespaceCount--;
292         }
293     }
294
295     /**
296       * Try and breakup a URI into a prefix and local part
297       *
298       * If $createNamespace is true, and the URI isn't part of an existing
299       * namespace, then EasyRdf will attempt to create a new namespace and
300       * return the name of the new prefix (for example 'ns0', 'term').
301       *
302       * If it isn't possible to split the URI, then null will be returned.
303       *
304       * @param string  $uri The full URI (eg 'http://xmlns.com/foaf/0.1/name')
305       * @param bool    $createNamespace If true, a new namespace will be created
306       * @return array  The split URI (eg 'foaf', 'name') or null
307       */
308     public static function splitUri($uri, $createNamespace = false)
309     {
310         if ($uri === null or $uri === '') {
311             throw new InvalidArgumentException(
312                 "\$uri cannot be null or empty"
313             );
314         }
315
316         if (is_object($uri) and ($uri instanceof EasyRdf_Resource)) {
317             $uri = $uri->getUri();
318         } elseif (!is_string($uri)) {
319             throw new InvalidArgumentException(
320                 "\$uri should be a string or EasyRdf_Resource"
321             );
322         }
323
324         foreach (self::namespaces() as $prefix => $long) {
325             if (substr($uri, 0, strlen($long)) !== $long) {
326                 continue;
327             }
328
329             $local_part = substr($uri, strlen($long));
330
331             if (strpos($local_part, '/') !== false) {
332                 // we can't have '/' in local part
333                 continue;
334             }
335
336             return array($prefix, $local_part);
337         }
338
339         if ($createNamespace) {
340             // Try and create a new namespace
341             # FIXME: check the valid characters for an XML element name
342             if (preg_match('/^(.+?)([\w\-]+)$/', $uri, $matches)) {
343                 $prefix = "ns".(self::$anonymousNamespaceCount++);
344                 self::set($prefix, $matches[1]);
345                 return array($prefix, $matches[2]);
346             }
347         }
348
349         return null;
350     }
351
352     /**
353       * Return the prefix namespace that a URI belongs to.
354       *
355       * @param string $uri A full URI (eg 'http://xmlns.com/foaf/0.1/name')
356       * @return string The prefix namespace that it is a part of(eg 'foaf')
357       */
358     public static function prefixOfUri($uri)
359     {
360         if ($parts = self::splitUri($uri)) {
361             return $parts[0];
362         }
363     }
364
365     /**
366       * Shorten a URI by substituting in the namespace prefix.
367       *
368       * If $createNamespace is true, and the URI isn't part of an existing
369       * namespace, then EasyRdf will attempt to create a new namespace and
370       * use that namespace to shorten the URI (for example ns0:term).
371       *
372       * If it isn't possible to shorten the URI, then null will be returned.
373       *
374       * @param string  $uri The full URI (eg 'http://xmlns.com/foaf/0.1/name')
375       * @param bool    $createNamespace If true, a new namespace will be created
376       * @return string The shortened URI (eg 'foaf:name') or null
377       */
378     public static function shorten($uri, $createNamespace = false)
379     {
380         if ($parts = self::splitUri($uri, $createNamespace)) {
381             return implode(':', $parts);
382         }
383     }
384
385     /**
386       * Expand a shortened URI (qname) back into a full URI.
387       *
388       * If it isn't possible to expand the qname, for example if the namespace
389       * isn't registered, then the original string will be returned.
390       *
391       * @param string $shortUri The short URI (eg 'foaf:name')
392       * @return string The full URI (eg 'http://xmlns.com/foaf/0.1/name')
393       */
394     public static function expand($shortUri)
395     {
396         if (!is_string($shortUri) or $shortUri === '') {
397             throw new InvalidArgumentException(
398                 "\$shortUri should be a string and cannot be null or empty"
399             );
400         }
401
402         if ($shortUri === 'a') {
403             $namespaces = self::namespaces();
404             return $namespaces['rdf'] . 'type';
405         } elseif (preg_match('/^(\w+?):([\w\-]+)$/', $shortUri, $matches)) {
406             $long = self::get($matches[1]);
407             if ($long) {
408                 return $long . $matches[2];
409             }
410         } elseif (preg_match('/^(\w+)$/', $shortUri) and isset(self::$default)) {
411             return self::$default . $shortUri;
412         }
413
414         return $shortUri;
415     }
416 }