699 lines
20 KiB
PHP
699 lines
20 KiB
PHP
<?php
|
|
|
|
/**
|
|
* EasyRdf
|
|
*
|
|
* LICENSE
|
|
*
|
|
* Copyright (c) 2009-2013 Nicholas J Humfrey. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
* 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
|
|
* promote products derived from this software without specific prior
|
|
* written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* @package EasyRdf
|
|
* @copyright Copyright (c) 2009-2013 Nicholas J Humfrey
|
|
* @license http://www.opensource.org/licenses/bsd-license.php
|
|
*/
|
|
|
|
/**
|
|
* Class the represents an RDF file format.
|
|
*
|
|
* For each format, the name, label, URIs and associated MIME Types are
|
|
* stored. A single parser and serialiser can also be registered to each
|
|
* format.
|
|
*
|
|
* @package EasyRdf
|
|
* @copyright Copyright (c) 2009-2013 Nicholas J Humfrey
|
|
* @license http://www.opensource.org/licenses/bsd-license.php
|
|
*/
|
|
class EasyRdf_Format
|
|
{
|
|
private static $formats = array();
|
|
|
|
private $name = array();
|
|
private $label = null;
|
|
private $uri = null;
|
|
private $mimeTypes = array();
|
|
private $extensions = array();
|
|
private $parserClass = null;
|
|
private $serialiserClass = null;
|
|
|
|
/** Get a list of format names
|
|
*
|
|
* @return array An array of formats name
|
|
*/
|
|
public static function getNames()
|
|
{
|
|
return array_keys(self::$formats);
|
|
}
|
|
|
|
/** Get a list of all the registered formats
|
|
*
|
|
* @return array An array of format objects
|
|
*/
|
|
public static function getFormats()
|
|
{
|
|
return self::$formats;
|
|
}
|
|
|
|
/** Generates an HTTP Accept header string
|
|
*
|
|
* The string will contain all of the MIME Types that we
|
|
* are able to parse.
|
|
*
|
|
* It is also possible to specify additional MIME types
|
|
* in the form array('text/plain' => 0.5) where 0.5 is the
|
|
* q value for that type. The types are sorted by q value
|
|
* before constructing the string.
|
|
*
|
|
* @param array $extraTypes extra MIME types to add
|
|
* @return string list of supported MIME types
|
|
*/
|
|
public static function getHttpAcceptHeader($extraTypes = array())
|
|
{
|
|
$accept = $extraTypes;
|
|
foreach (self::$formats as $format) {
|
|
if ($format->parserClass and count($format->mimeTypes) > 0) {
|
|
$accept = array_merge($accept, $format->mimeTypes);
|
|
}
|
|
}
|
|
arsort($accept, SORT_NUMERIC);
|
|
|
|
$acceptStr='';
|
|
foreach ($accept as $type => $q) {
|
|
if ($acceptStr) {
|
|
$acceptStr .= ',';
|
|
}
|
|
if ($q == 1.0) {
|
|
$acceptStr .= $type;
|
|
} else {
|
|
$acceptStr .= sprintf("%s;q=%1.1F", $type, $q);
|
|
}
|
|
}
|
|
return $acceptStr;
|
|
}
|
|
|
|
/** Check if a named graph exists
|
|
*
|
|
* @param string $name the name of the format
|
|
* @return boolean true if the format exists
|
|
*/
|
|
public static function formatExists($name)
|
|
{
|
|
return array_key_exists($name, self::$formats);
|
|
}
|
|
|
|
/** Get a EasyRdf_Format from a name, uri or mime type
|
|
*
|
|
* @param string $query a query string to search for
|
|
* @return object the first EasyRdf_Format that matches the query
|
|
* @throws EasyRdf_Exception if no format is found
|
|
*/
|
|
public static function getFormat($query)
|
|
{
|
|
if (!is_string($query) or $query == null or $query == '') {
|
|
throw new InvalidArgumentException(
|
|
"\$query should be a string and cannot be null or empty"
|
|
);
|
|
}
|
|
|
|
foreach (self::$formats as $format) {
|
|
if ($query == $format->name or
|
|
$query == $format->uri or
|
|
array_key_exists($query, $format->mimeTypes) or
|
|
in_array($query, $format->extensions)) {
|
|
return $format;
|
|
}
|
|
}
|
|
|
|
# No match
|
|
throw new EasyRdf_Exception(
|
|
"Format is not recognised: $query"
|
|
);
|
|
}
|
|
|
|
/** Register a new format
|
|
*
|
|
* @param string $name The name of the format (e.g. ntriples)
|
|
* @param string $label The label for the format (e.g. N-Triples)
|
|
* @param string $uri The URI for the format
|
|
* @param string $mimeTypes One or more mime types for the format
|
|
* @param string $extensions One or more extensions (file suffix)
|
|
* @return object The new EasyRdf_Format object
|
|
*/
|
|
public static function register(
|
|
$name,
|
|
$label = null,
|
|
$uri = null,
|
|
$mimeTypes = array(),
|
|
$extensions = array()
|
|
) {
|
|
if (!is_string($name) or $name == null or $name == '') {
|
|
throw new InvalidArgumentException(
|
|
"\$name should be a string and cannot be null or empty"
|
|
);
|
|
}
|
|
|
|
if (!array_key_exists($name, self::$formats)) {
|
|
self::$formats[$name] = new EasyRdf_Format($name);
|
|
}
|
|
|
|
self::$formats[$name]->setLabel($label);
|
|
self::$formats[$name]->setUri($uri);
|
|
self::$formats[$name]->setMimeTypes($mimeTypes);
|
|
self::$formats[$name]->setExtensions($extensions);
|
|
return self::$formats[$name];
|
|
}
|
|
|
|
/** Remove a format from the registry
|
|
*
|
|
* @param string $name The name of the format (e.g. ntriples)
|
|
*/
|
|
public static function unregister($name)
|
|
{
|
|
unset(self::$formats[$name]);
|
|
}
|
|
|
|
/** Class method to register a parser class to a format name
|
|
*
|
|
* @param string $name The name of the format (e.g. ntriples)
|
|
* @param string $class The name of the class (e.g. EasyRdf_Parser_Ntriples)
|
|
*/
|
|
public static function registerParser($name, $class)
|
|
{
|
|
if (!self::formatExists($name)) {
|
|
self::register($name);
|
|
}
|
|
self::getFormat($name)->setParserClass($class);
|
|
}
|
|
|
|
/** Class method to register a serialiser class to a format name
|
|
*
|
|
* @param string $name The name of the format (e.g. ntriples)
|
|
* @param string $class The name of the class (e.g. EasyRdf_Serialiser_Ntriples)
|
|
*/
|
|
public static function registerSerialiser($name, $class)
|
|
{
|
|
if (!self::formatExists($name)) {
|
|
self::register($name);
|
|
}
|
|
self::getFormat($name)->setSerialiserClass($class);
|
|
}
|
|
|
|
/** Attempt to guess the document format from some content.
|
|
*
|
|
* If $filename is given, then the suffix is first used to guess the format.
|
|
*
|
|
* If the document format is not recognised, null is returned.
|
|
*
|
|
* @param string $data The document data
|
|
* @param string $filename Optional filename
|
|
* @return object EasyRdf_Format The format object
|
|
*/
|
|
public static function guessFormat($data, $filename = null)
|
|
{
|
|
if (is_array($data)) {
|
|
# Data has already been parsed into RDF/PHP
|
|
return self::getFormat('php');
|
|
}
|
|
|
|
// First try and identify by the filename
|
|
if ($filename and preg_match('/\.(\w+)$/', $filename, $matches)) {
|
|
foreach (self::$formats as $format) {
|
|
if (in_array($matches[1], $format->extensions)) {
|
|
return $format;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Then try and guess by the first 1024 bytes of content
|
|
$short = substr($data, 0, 1024);
|
|
if (preg_match('/^\s*\{/', $short)) {
|
|
return self::getFormat('json');
|
|
} elseif (preg_match('/<rdf:/i', $short)) {
|
|
return self::getFormat('rdfxml');
|
|
} elseif (preg_match('|http://www.w3.org/2005/sparql-results|', $short)) {
|
|
return self::getFormat('sparql-xml');
|
|
} elseif (preg_match('/\WRDFa\W/i', $short)) {
|
|
return self::getFormat('rdfa');
|
|
} elseif (preg_match('/<!DOCTYPE html|<html/i', $short)) {
|
|
# We don't support any other microformats embedded in HTML
|
|
return self::getFormat('rdfa');
|
|
} elseif (preg_match('/@prefix\s|@base\s/', $short)) {
|
|
return self::getFormat('turtle');
|
|
} elseif (preg_match('/^\s*<.+> <.+>/m', $short)) {
|
|
return self::getFormat('ntriples');
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This constructor is for internal use only.
|
|
* To create a new format, use the register method.
|
|
*
|
|
* @param string $name The name of the format
|
|
* @see EasyRdf_Format::register()
|
|
* @ignore
|
|
*/
|
|
public function __construct($name)
|
|
{
|
|
$this->name = $name;
|
|
$this->label = $name; # Only a default
|
|
}
|
|
|
|
/** Get the name of a format object
|
|
*
|
|
* @return string The name of the format (e.g. rdfxml)
|
|
*/
|
|
public function getName()
|
|
{
|
|
return $this->name;
|
|
}
|
|
|
|
/** Get the label for a format object
|
|
*
|
|
* @return string The format label (e.g. RDF/XML)
|
|
*/
|
|
public function getLabel()
|
|
{
|
|
return $this->label;
|
|
}
|
|
|
|
/** Set the label for a format object
|
|
*
|
|
* @param string $label The new label for the format
|
|
*/
|
|
public function setLabel($label)
|
|
{
|
|
if ($label) {
|
|
if (!is_string($label)) {
|
|
throw new InvalidArgumentException(
|
|
"\$label should be a string"
|
|
);
|
|
}
|
|
return $this->label = $label;
|
|
} else {
|
|
return $this->label = null;
|
|
}
|
|
}
|
|
|
|
/** Get the URI for a format object
|
|
*
|
|
* @return string The format URI
|
|
*/
|
|
public function getUri()
|
|
{
|
|
return $this->uri;
|
|
}
|
|
|
|
/** Set the URI for a format object
|
|
*
|
|
* @param string $uri The new URI for the format
|
|
*/
|
|
public function setUri($uri)
|
|
{
|
|
if ($uri) {
|
|
if (!is_string($uri)) {
|
|
throw new InvalidArgumentException(
|
|
"\$uri should be a string"
|
|
);
|
|
}
|
|
return $this->uri = $uri;
|
|
} else {
|
|
return $this->uri = null;
|
|
}
|
|
}
|
|
|
|
/** Get the default registered mime type for a format object
|
|
*
|
|
* @return string The default mime type as a string.
|
|
*/
|
|
public function getDefaultMimeType()
|
|
{
|
|
$types = array_keys($this->mimeTypes);
|
|
if (isset($types[0])) {
|
|
return $types[0];
|
|
}
|
|
}
|
|
|
|
/** Get all the registered mime types for a format object
|
|
*
|
|
* @return array One or more MIME types in an array with
|
|
* the mime type as the key and q value as the value
|
|
*/
|
|
public function getMimeTypes()
|
|
{
|
|
return $this->mimeTypes;
|
|
}
|
|
|
|
/** Set the MIME Types for a format object
|
|
*
|
|
* @param array $mimeTypes One or more mime types
|
|
*/
|
|
public function setMimeTypes($mimeTypes)
|
|
{
|
|
if ($mimeTypes) {
|
|
if (!is_array($mimeTypes)) {
|
|
$mimeTypes = array($mimeTypes);
|
|
}
|
|
$this->mimeTypes = $mimeTypes;
|
|
} else {
|
|
$this->mimeTypes = array();
|
|
}
|
|
}
|
|
|
|
/** Get the default registered file extension (filename suffix) for a format object
|
|
*
|
|
* @return string The default extension as a string.
|
|
*/
|
|
public function getDefaultExtension()
|
|
{
|
|
if (isset($this->extensions[0])) {
|
|
return $this->extensions[0];
|
|
}
|
|
}
|
|
|
|
/** Get all the registered file extensions (filename suffix) for a format object
|
|
*
|
|
* @return array One or more extensions as an array
|
|
*/
|
|
public function getExtensions()
|
|
{
|
|
return $this->extensions;
|
|
}
|
|
|
|
/** Set the file format extensions (filename suffix) for a format object
|
|
*
|
|
* @param mixed $extensions One or more file extensions
|
|
*/
|
|
public function setExtensions($extensions)
|
|
{
|
|
if ($extensions) {
|
|
if (!is_array($extensions)) {
|
|
$extensions = array($extensions);
|
|
}
|
|
$this->extensions = $extensions;
|
|
} else {
|
|
$this->extensions = array();
|
|
}
|
|
}
|
|
|
|
/** Set the parser to use for a format
|
|
*
|
|
* @param string $class The name of the class
|
|
*/
|
|
public function setParserClass($class)
|
|
{
|
|
if ($class) {
|
|
if (!is_string($class)) {
|
|
throw new InvalidArgumentException(
|
|
"\$class should be a string"
|
|
);
|
|
}
|
|
$this->parserClass = $class;
|
|
} else {
|
|
$this->parserClass = null;
|
|
}
|
|
}
|
|
|
|
/** Get the name of the class to use to parse the format
|
|
*
|
|
* @return string The name of the class
|
|
*/
|
|
public function getParserClass()
|
|
{
|
|
return $this->parserClass;
|
|
}
|
|
|
|
/** Create a new parser to parse this format
|
|
*
|
|
* @return object The new parser object
|
|
*/
|
|
public function newParser()
|
|
{
|
|
$parserClass = $this->parserClass;
|
|
if (!$parserClass) {
|
|
throw new EasyRdf_Exception(
|
|
"No parser class available for format: ".$this->getName()
|
|
);
|
|
}
|
|
return (new $parserClass());
|
|
}
|
|
|
|
/** Set the serialiser to use for a format
|
|
*
|
|
* @param string $class The name of the class
|
|
*/
|
|
public function setSerialiserClass($class)
|
|
{
|
|
if ($class) {
|
|
if (!is_string($class)) {
|
|
throw new InvalidArgumentException(
|
|
"\$class should be a string"
|
|
);
|
|
}
|
|
$this->serialiserClass = $class;
|
|
} else {
|
|
$this->serialiserClass = null;
|
|
}
|
|
}
|
|
|
|
/** Get the name of the class to use to serialise the format
|
|
*
|
|
* @return string The name of the class
|
|
*/
|
|
public function getSerialiserClass()
|
|
{
|
|
return $this->serialiserClass;
|
|
}
|
|
|
|
/** Create a new serialiser to parse this format
|
|
*
|
|
* @return object The new serialiser object
|
|
*/
|
|
public function newSerialiser()
|
|
{
|
|
$serialiserClass = $this->serialiserClass;
|
|
if (!$serialiserClass) {
|
|
throw new EasyRdf_Exception(
|
|
"No serialiser class available for format: ".$this->getName()
|
|
);
|
|
}
|
|
return (new $serialiserClass());
|
|
}
|
|
|
|
/** Magic method to return the name of the format when casted to string
|
|
*
|
|
* @return string The name of the format
|
|
*/
|
|
public function __toString()
|
|
{
|
|
return $this->name;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Register default set of supported formats
|
|
NOTE: they are ordered by preference
|
|
*/
|
|
|
|
EasyRdf_Format::register(
|
|
'php',
|
|
'RDF/PHP',
|
|
'http://n2.talis.com/wiki/RDF_PHP_Specification',
|
|
array(
|
|
'application/x-httpd-php-source' => 1.0
|
|
),
|
|
array('phps')
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'json',
|
|
'RDF/JSON Resource-Centric',
|
|
'http://n2.talis.com/wiki/RDF_JSON_Specification',
|
|
array(
|
|
'application/json' => 1.0,
|
|
'text/json' => 0.9,
|
|
'application/rdf+json' => 0.9
|
|
),
|
|
array('json')
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'jsonld',
|
|
'JSON-LD',
|
|
'http://www.w3.org/TR/json-ld/',
|
|
array(
|
|
'application/ld+json' => 1.0
|
|
),
|
|
array('jsonld')
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'ntriples',
|
|
'N-Triples',
|
|
'http://www.w3.org/TR/n-triples/',
|
|
array(
|
|
'application/n-triples' => 1.0,
|
|
'text/plain' => 0.9,
|
|
'text/ntriples' => 0.9,
|
|
'application/ntriples' => 0.9,
|
|
'application/x-ntriples' => 0.9
|
|
),
|
|
array('nt')
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'turtle',
|
|
'Turtle Terse RDF Triple Language',
|
|
'http://www.dajobe.org/2004/01/turtle',
|
|
array(
|
|
'text/turtle' => 0.8,
|
|
'application/turtle' => 0.7,
|
|
'application/x-turtle' => 0.7
|
|
),
|
|
array('ttl')
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'rdfxml',
|
|
'RDF/XML',
|
|
'http://www.w3.org/TR/rdf-syntax-grammar',
|
|
array(
|
|
'application/rdf+xml' => 0.8
|
|
),
|
|
array('rdf', 'xrdf')
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'dot',
|
|
'Graphviz',
|
|
'http://www.graphviz.org/doc/info/lang.html',
|
|
array(
|
|
'text/vnd.graphviz' => 0.8
|
|
),
|
|
array('gv', 'dot')
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'json-triples',
|
|
'RDF/JSON Triples'
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'n3',
|
|
'Notation3',
|
|
'http://www.w3.org/2000/10/swap/grammar/n3#',
|
|
array(
|
|
'text/n3' => 0.5,
|
|
'text/rdf+n3' => 0.5
|
|
),
|
|
array('n3')
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'rdfa',
|
|
'RDFa',
|
|
'http://www.w3.org/TR/rdfa-core/',
|
|
array(
|
|
'text/html' => 0.4,
|
|
'application/xhtml+xml' => 0.4
|
|
),
|
|
array('html')
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'sparql-xml',
|
|
'SPARQL XML Query Results',
|
|
'http://www.w3.org/TR/rdf-sparql-XMLres/',
|
|
array(
|
|
'application/sparql-results+xml' => 1.0
|
|
)
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'sparql-json',
|
|
'SPARQL JSON Query Results',
|
|
'http://www.w3.org/TR/rdf-sparql-json-res/',
|
|
array(
|
|
'application/sparql-results+json' => 1.0
|
|
)
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'png',
|
|
'Portable Network Graphics (PNG)',
|
|
'http://www.w3.org/TR/PNG/',
|
|
array(
|
|
'image/png' => 0.3
|
|
),
|
|
array('png')
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'gif',
|
|
'Graphics Interchange Format (GIF)',
|
|
'http://www.w3.org/Graphics/GIF/spec-gif89a.txt',
|
|
array(
|
|
'image/gif' => 0.2
|
|
),
|
|
array('gif')
|
|
);
|
|
|
|
EasyRdf_Format::register(
|
|
'svg',
|
|
'Scalable Vector Graphics (SVG)',
|
|
'http://www.w3.org/TR/SVG/',
|
|
array(
|
|
'image/svg+xml' => 0.3
|
|
),
|
|
array('svg')
|
|
);
|
|
|
|
|
|
/*
|
|
Register default set of parsers and serialisers
|
|
*/
|
|
|
|
EasyRdf_Format::registerParser('json', 'EasyRdf_Parser_Json');
|
|
EasyRdf_Format::registerParser('jsonld', 'EasyRdf_Parser_JsonLd');
|
|
EasyRdf_Format::registerParser('ntriples', 'EasyRdf_Parser_Ntriples');
|
|
EasyRdf_Format::registerParser('php', 'EasyRdf_Parser_RdfPhp');
|
|
EasyRdf_Format::registerParser('rdfxml', 'EasyRdf_Parser_RdfXml');
|
|
EasyRdf_Format::registerParser('turtle', 'EasyRdf_Parser_Turtle');
|
|
EasyRdf_Format::registerParser('rdfa', 'EasyRdf_Parser_Rdfa');
|
|
|
|
EasyRdf_Format::registerSerialiser('json', 'EasyRdf_Serialiser_Json');
|
|
EasyRdf_Format::registerSerialiser('jsonld', 'EasyRdf_Serialiser_JsonLd');
|
|
EasyRdf_Format::registerSerialiser('n3', 'EasyRdf_Serialiser_Turtle');
|
|
EasyRdf_Format::registerSerialiser('ntriples', 'EasyRdf_Serialiser_Ntriples');
|
|
EasyRdf_Format::registerSerialiser('php', 'EasyRdf_Serialiser_RdfPhp');
|
|
EasyRdf_Format::registerSerialiser('rdfxml', 'EasyRdf_Serialiser_RdfXml');
|
|
EasyRdf_Format::registerSerialiser('turtle', 'EasyRdf_Serialiser_Turtle');
|
|
|
|
EasyRdf_Format::registerSerialiser('dot', 'EasyRdf_Serialiser_GraphViz');
|
|
EasyRdf_Format::registerSerialiser('gif', 'EasyRdf_Serialiser_GraphViz');
|
|
EasyRdf_Format::registerSerialiser('png', 'EasyRdf_Serialiser_GraphViz');
|
|
EasyRdf_Format::registerSerialiser('svg', 'EasyRdf_Serialiser_GraphViz');
|