mirror of
https://github.com/JHUAPL/aqueduct.git
synced 2026-01-06 22:44:01 -05:00
Aqueduct 1.2 release for repo upload
This commit is contained in:
283
AqueductExtension.php
Normal file
283
AqueductExtension.php
Normal file
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
//Begin profiling
|
||||
aqProfile("aq");
|
||||
|
||||
//Put settings here so they can be modified easily
|
||||
$wgAqueductTblname = "aqueduct";
|
||||
$wgAqueductQueryTblname = "aqueductqueries";
|
||||
$wgAqueductOldNSTblname = "aqueductoldnamespaces";
|
||||
|
||||
//Set up PHP options
|
||||
ini_set("soap.wsdl_cache_enabled", "0");
|
||||
|
||||
$dir = dirname(__FILE__) . '/includes/';
|
||||
//Set up general extension settings
|
||||
$wgExtensionCredits['specialpage'][] = array(
|
||||
'name' => 'Aqueduct Extension',
|
||||
'author' => 'The Johns Hopkins University Applied Physics Laboratory',
|
||||
'description' => 'A Mediawiki-based platform that allows users to explore, visualize, and annotate external RDF data sources within a wiki interface',
|
||||
'version' => 1.2
|
||||
);
|
||||
|
||||
//Set up the special page
|
||||
$wgExtensionMessagesFiles['AqueductExtension'] = $dir . 'AqueductExtension.i18n.php';
|
||||
$wgAutoloadClasses['SpecialAqueductConfiguration'] = $dir . 'SpecialAqueductConfiguration.php';
|
||||
$wgSpecialPages['AqueductConfiguration'] = 'SpecialAqueductConfiguration';
|
||||
|
||||
//Set up the Aqueduct API
|
||||
$wgAutoloadClasses['ApiAqueduct'] = $dir . 'ApiAqueduct.php';
|
||||
$wgAPIModules['aqueduct'] = 'ApiAqueduct';
|
||||
|
||||
//Set up the Aqueduct Set API
|
||||
$wgAutoloadClasses['ApiAqueductSet'] = $dir . 'ApiAqueductSet.php';
|
||||
$wgAPIModules['aqueductset'] = 'ApiAqueductSet';
|
||||
|
||||
// Article prepopulation extension
|
||||
require_once($dir . 'AqueductPagePopulation.php');
|
||||
require_once($dir . 'AqueductEditPage.php');
|
||||
|
||||
// Set up the hook to interupt the edit to check for a new page creation.
|
||||
$wgHooks['EditPage::showEditForm:initial'][] = 'aqEditWidgetTagHelp';
|
||||
$wgHooks['AlternateEdit'][] = 'aqEditWidgetTagJS';
|
||||
$wgHooks['AlternateEdit'][] = 'aqPopulateNewPage';
|
||||
|
||||
//Register a hook to set up the user-configured Mediawiki namespaces
|
||||
$wgHooks['SetupAfterCache'][] = 'wfAqueductSetupNS';
|
||||
|
||||
//Load the file with the widget tag logic
|
||||
require_once($dir . 'WidgetTags.php');
|
||||
|
||||
//Register the general extension init code (used to set up the widget parser tags)
|
||||
if ( defined( 'MW_SUPPORTS_PARSERFIRSTCALLINIT' ) ) {
|
||||
$wgHooks['ParserFirstCallInit'][] = 'wfAqueductExtension';
|
||||
}
|
||||
else { // Otherwise do things the old fashioned way
|
||||
$wgExtensionFunctions[] = "wfAqueductExtension";
|
||||
}
|
||||
|
||||
//Register the magic word init code (used to set up the parser function alias)
|
||||
$wgHooks['LanguageGetMagic'][] = 'wfAqueductExtensionSetMagicWords';
|
||||
|
||||
|
||||
aqProfile("mw");
|
||||
|
||||
//Function and class definitions go below
|
||||
|
||||
//Set up the user-defined Aqueduct namespaces (this must be called early in Mediawiki's init)
|
||||
function wfAqueductSetupNS()
|
||||
{
|
||||
global $wgAqueductTblname, $wgCanonicalNamespaceNames, $wgExtraNamespaces, $wgAqueductQueryTblname, $wgAqueductOldNSTblname;
|
||||
//Don't use DB functions because that file is not loaded here...
|
||||
aqProfile("aq");
|
||||
$newNamespaces = array();
|
||||
$db =& wfGetDB( DB_SLAVE );
|
||||
|
||||
$res = $db->select($wgAqueductTblname, '*');
|
||||
while($row = $db->fetchRow($res))
|
||||
{
|
||||
if (intval($row['aq_wiki_namespace_id'])!=0)
|
||||
{
|
||||
$newNamespaces[intval($row['aq_wiki_namespace_id'])] = $row['aq_wiki_namespace'];
|
||||
$newNamespaces[intval($row['aq_wiki_namespace_id'])+1] = $row['aq_wiki_namespace'].'_talk';
|
||||
}
|
||||
}
|
||||
$db->freeResult($res);
|
||||
|
||||
$res = $db->select($wgAqueductOldNSTblname, '*');
|
||||
while($row = $db->fetchRow($res))
|
||||
{
|
||||
if (intval($row['aq_wiki_namespace_id'])!=0)
|
||||
{
|
||||
$newNamespaces[intval($row['aq_wiki_namespace_id'])] = $row['aq_wiki_namespace'];
|
||||
$newNamespaces[intval($row['aq_wiki_namespace_id'])+1] = $row['aq_wiki_namespace'].'_talk';
|
||||
}
|
||||
}
|
||||
$db->freeResult($res);
|
||||
|
||||
$res = $db->select($wgAqueductQueryTblname, '*');
|
||||
while($row = $db->fetchRow($res))
|
||||
{
|
||||
if (intval($row['aq_wiki_namespace_id'])!=0)
|
||||
{
|
||||
$newNamespaces[intval($row['aq_wiki_namespace_id'])] = $row['aq_wiki_parent_namespace'] . '_' . $row['aq_wiki_namespace_tag'];
|
||||
$newNamespaces[intval($row['aq_wiki_namespace_id'])+1] = $row['aq_wiki_parent_namespace'] . '_' . $row['aq_wiki_namespace_tag'] . '_talk';
|
||||
}
|
||||
}
|
||||
$db->freeResult($res);
|
||||
|
||||
if (!is_array($wgExtraNamespaces))
|
||||
{
|
||||
$wgExtraNamespaces = array();
|
||||
}
|
||||
$wgExtraNamespaces = $wgExtraNamespaces + $newNamespaces;
|
||||
$wgCanonicalNamespaceNames = $wgCanonicalNamespaceNames + $newNamespaces;
|
||||
aqProfile("mw");
|
||||
return true;
|
||||
}
|
||||
|
||||
//Extension initialization function (normally used to set up parser tags)
|
||||
function wfAqueductExtension()
|
||||
{
|
||||
global $wgParser,$wgAqueductLayoutMode,$wgDefaultSkin,$wgAqueductJSFiles,$wgRequest,$wgTitle,$wgOut,$wgScriptPath;
|
||||
aqProfile("aq");
|
||||
wfAqueductSetParserHooks($wgParser);
|
||||
//Only do this once (multiple parser init will be called if we are displaying a compound page)
|
||||
if (!isset($wgAqueductLayoutMode))
|
||||
{
|
||||
//Figure out if we are using the gridbook skin; if so, go into layout mode
|
||||
$wgAqueductLayoutMode =
|
||||
($wgDefaultSkin == 'gridbook' &&
|
||||
$wgRequest->getText( 'action', 'view' ) == 'view' &&
|
||||
$wgTitle->getNamespace()>-1);
|
||||
if ($wgAqueductLayoutMode)
|
||||
{
|
||||
if (!$wgAqueductJSFiles)
|
||||
{
|
||||
$wgAqueductJSFiles = array();
|
||||
}
|
||||
//Force a bunch of JS and CSS files to load even if there are no widgets on the page because we are in layout mode
|
||||
$wgAqueductJSFiles['jquery-1.3.2.min.js'] = false;
|
||||
$wgAqueductJSFiles['jquery-ui-1.7.2.custom.min.js'] = false;
|
||||
$wgAqueductJSFiles['jquery.layout.min-1.2.0.js'] = false;
|
||||
$wgAqueductJSFiles['gridPlacement.js'] = false;
|
||||
$wgAqueductJSScripts['<link type="text/css" href="'.$wgScriptPath.'/extensions/AqueductExtension/widget/js/aqueduct-layout.css" rel="Stylesheet" />'] = false;
|
||||
$wgOut->addScriptFile($wgScriptPath. '/extensions/AqueductExtension/widget/js/jquery-1.3.2.min.js');
|
||||
$wgOut->addScriptFile($wgScriptPath. '/extensions/AqueductExtension/widget/js/jquery-ui-1.7.2.custom.min.js');
|
||||
$wgOut->addScriptFile($wgScriptPath. '/extensions/AqueductExtension/widget/js/jquery.layout.min-1.2.0.js');
|
||||
$wgOut->addScriptFile($wgScriptPath. '/extensions/AqueductExtension/widget/js/gridPlacement.js');
|
||||
$wgOut->addScript('<link type="text/css" href="'.$wgScriptPath.'/extensions/AqueductExtension/widget/js/aqueduct-layout.css" rel="Stylesheet" />' . "\n");
|
||||
}
|
||||
}
|
||||
aqProfile("mw");
|
||||
return true;
|
||||
}
|
||||
|
||||
function aqSetHook($parser, $name, $function, $description)
|
||||
{
|
||||
global $wgAqueductWidgetTags;
|
||||
|
||||
// Initiate the array
|
||||
if (!isset($wgAqueductWidgetTags) || !is_array($wgAqueductWidgetTags))
|
||||
$wgAqueductWidgetTags = array();
|
||||
|
||||
// store the description
|
||||
$wgAqueductWidgetTags["$name"] = "$description";
|
||||
|
||||
// Add to the parser hooks
|
||||
// if parser is null, then only initiate the descriptions!
|
||||
if ($parser !== null)
|
||||
$parser->setHook( $name, $function );
|
||||
}
|
||||
|
||||
function aqSetAdvHook($parser, $name, $function, $description)
|
||||
{
|
||||
global $wgAqueductAdvWidgetTags;
|
||||
|
||||
// Initiate the array
|
||||
if (!isset($wgAqueductAdvWidgetTags) || !is_array($wgAqueductAdvWidgetTags))
|
||||
$wgAqueductAdvWidgetTags = array();
|
||||
|
||||
// store the description
|
||||
$wgAqueductAdvWidgetTags["$name"] = "$description";
|
||||
|
||||
// Add to the parser hooks
|
||||
// if parser is null, then only initiate the descriptions!
|
||||
if ($parser !== null)
|
||||
$parser->setHook( $name, $function );
|
||||
}
|
||||
|
||||
function wfAqueductSetParserHooks($parser)
|
||||
{
|
||||
global $wgEnableLayoutWidgets,$wgEnableCustomScripts;
|
||||
aqSetHook($parser, "aqProfile", "aqProfileTag", "Display profiling output for a page's Aqueduct operations." );
|
||||
aqSetHook($parser, "aqRawWidget", "aqRawWidgetTag", "Place a Raw Format widget. Each row represents an RDF triple." );
|
||||
aqSetHook($parser, "aqTableViewWidget", "aqTableViewWidgetTag", "Place a Table Format widget. Each row represents an entity, and each column contains fields about that entity." );
|
||||
aqSetHook($parser, "aqNetworkViewWidget", "aqNetworkViewWidgetTag", "Place a Google Earth widget. Displays data with geospatial information as markers." );
|
||||
aqSetHook($parser, "aqNetworkViewWidget2D", "aqNetworkViewWidget2DTag", "Place a Google Map widget. Displays data with geospatial information as markers." );
|
||||
aqSetAdvHook($parser, "aqIncludeWidgets", "aqIncludeWidgetsTag", "Takes a WikiTitle as input and includes all widgets from that page." );
|
||||
aqSetAdvHook($parser, "aqAddData", "aqAddDataTag", "Takes a WikiTitle as input and includes all data from that page into widgets on this page." );
|
||||
aqSetAdvHook($parser, "aqAddQuery", "aqAddQueryTag", "Takes a SPARQL query as input to execute." );
|
||||
aqSetAdvHook($parser, "aqWikiText", "aqWikiTextTag", "Indicates where wikitext should be displayed in a grid-mode page." );
|
||||
|
||||
if ($wgEnableCustomScripts )
|
||||
{
|
||||
aqSetAdvHook($parser, "aqAddHeader", "aqHeaderTag", "Adds a Javascript file to the page." );
|
||||
aqSetAdvHook($parser, "aqAddScript", "aqScriptTag", "Adds a Javascript script to the page." );
|
||||
}
|
||||
if ($wgEnableLayoutWidgets)
|
||||
{
|
||||
aqSetAdvHook($parser, "aqLayout", "aqLayoutTag", "Inserts a layout to be used by a Layout widget." );
|
||||
aqSetHook($parser, "aqLayoutWidget", "aqLayoutWidgetTag", "Uses the layout inserted into a page via 'aqLayout' to display RDF." );
|
||||
}
|
||||
|
||||
if ($parser !== null)
|
||||
$parser->setFunctionHook( 'triplemagicword', 'aqAddTripleTag' );
|
||||
}
|
||||
|
||||
function wfAqueductExtensionSetMagicWords( &$magicWords, $langCode )
|
||||
{
|
||||
$magicWords['triplemagicword'] = array( 0, 'triple' );
|
||||
return true;
|
||||
}
|
||||
|
||||
function aqProfile($newmode)
|
||||
{
|
||||
global $wgAqueductProfile;
|
||||
if ($wgAqueductProfile === TRUE)
|
||||
{
|
||||
global $aqProfileMode, $aqProfileStart, $aqProfileData;
|
||||
$endtime = microtime(TRUE);
|
||||
if ($aqProfileMode)
|
||||
{
|
||||
if (!$aqProfileData)
|
||||
{
|
||||
$aqProfileData = array();
|
||||
}
|
||||
if (array_key_exists($aqProfileMode,$aqProfileData))
|
||||
{
|
||||
$oldtime = $aqProfileData[$aqProfileMode];
|
||||
}
|
||||
else
|
||||
{
|
||||
$oldtime = 0.0;
|
||||
}
|
||||
$totaltime = $endtime - $aqProfileStart;
|
||||
$aqProfileData[$aqProfileMode] = $oldtime + $totaltime;
|
||||
}
|
||||
$aqProfileMode = $newmode;
|
||||
$aqProfileStart = microtime(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
function aqProfileTag()
|
||||
{
|
||||
global $aqProfileData;
|
||||
$out = print_r($aqProfileData,TRUE);
|
||||
$aqProfileData = null;
|
||||
return $out;
|
||||
}
|
||||
|
||||
?>
|
||||
32
AqueductSQLTbl.sql
Normal file
32
AqueductSQLTbl.sql
Normal file
@@ -0,0 +1,32 @@
|
||||
create table aqueduct
|
||||
(
|
||||
aq_wiki_namespace varchar(100) primary key,
|
||||
aq_wiki_namespace_id int unique,
|
||||
aq_source_uri varchar(100) unique,
|
||||
aq_source_type varchar(10),
|
||||
aq_source_name varchar(100),
|
||||
aq_source_location varchar(100),
|
||||
aq_source_cert_path varchar(100),
|
||||
aq_source_cert_pass varchar(100),
|
||||
aq_initial_lowercase int,
|
||||
aq_search_fragments int
|
||||
);
|
||||
|
||||
create table aqueductqueries
|
||||
(
|
||||
aq_wiki_namespace_id int primary key,
|
||||
aq_wiki_parent_namespace varchar(100) references aqueduct(aq_wiki_namespace),
|
||||
aq_wiki_namespace_tag varchar(100),
|
||||
aq_query_type varchar(100),
|
||||
aq_datasource varchar(100),
|
||||
aq_query varchar(2000),
|
||||
aq_algorithm varchar(100),
|
||||
aq_query_uri_param int
|
||||
);
|
||||
|
||||
|
||||
create table aqueductoldnamespaces
|
||||
(
|
||||
aq_wiki_namespace_id int primary key,
|
||||
aq_wiki_namespace varchar(100) unique
|
||||
);
|
||||
501
GridBook.php
Normal file
501
GridBook.php
Normal file
@@ -0,0 +1,501 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/**
|
||||
* MonoBook nouveau
|
||||
*
|
||||
* Translated from gwicke's previous TAL template version to remove
|
||||
* dependency on PHPTAL.
|
||||
*
|
||||
* @todo document
|
||||
* @file
|
||||
* @ingroup Skins
|
||||
*/
|
||||
|
||||
if( !defined( 'MEDIAWIKI' ) )
|
||||
die( -1 );
|
||||
|
||||
/**
|
||||
* Inherit main code from SkinTemplate, set the CSS and template filter.
|
||||
* @todo document
|
||||
* @ingroup Skins
|
||||
*/
|
||||
class SkinGridBook extends SkinTemplate {
|
||||
/** Using monobook. */
|
||||
function initPage( OutputPage $out ) {
|
||||
parent::initPage( $out );
|
||||
$this->skinname = 'gridbook';
|
||||
$this->stylename = 'gridbook';
|
||||
$this->template = 'GridBookTemplate';
|
||||
|
||||
}
|
||||
|
||||
function setupSkinUserCss( OutputPage $out ) {
|
||||
global $wgHandheldStyle;
|
||||
|
||||
parent::setupSkinUserCss( $out );
|
||||
|
||||
// Append to the default screen common & print styles...
|
||||
$out->addStyle( 'monobook/main.css', 'screen' );
|
||||
if( $wgHandheldStyle ) {
|
||||
// Currently in testing... try 'chick/main.css'
|
||||
$out->addStyle( $wgHandheldStyle, 'handheld' );
|
||||
}
|
||||
|
||||
$out->addStyle( 'monobook/IE50Fixes.css', 'screen', 'lt IE 5.5000' );
|
||||
$out->addStyle( 'monobook/IE55Fixes.css', 'screen', 'IE 5.5000' );
|
||||
$out->addStyle( 'monobook/IE60Fixes.css', 'screen', 'IE 6' );
|
||||
$out->addStyle( 'monobook/IE70Fixes.css', 'screen', 'IE 7' );
|
||||
|
||||
$out->addStyle( 'monobook/rtl.css', 'screen', '', 'rtl' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo document
|
||||
* @ingroup Skins
|
||||
*/
|
||||
class GridBookTemplate extends QuickTemplate {
|
||||
var $skin;
|
||||
/**
|
||||
* Template filter callback for MonoBook skin.
|
||||
* Takes an associative array of data set from a SkinTemplate-based
|
||||
* class, and a wrapper for MediaWiki's localization database, and
|
||||
* outputs a formatted page.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function execute() {
|
||||
global $wgRequest;
|
||||
$this->skin = $skin = $this->data['skin'];
|
||||
$action = $wgRequest->getText( 'action' );
|
||||
|
||||
// Suppress warnings to prevent notices about missing indexes in $this->data
|
||||
wfSuppressWarnings();
|
||||
|
||||
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="<?php $this->text('xhtmldefaultnamespace') ?>" <?php
|
||||
foreach($this->data['xhtmlnamespaces'] as $tag => $ns) {
|
||||
?>xmlns:<?php echo "{$tag}=\"{$ns}\" ";
|
||||
} ?>xml:lang="<?php $this->text('lang') ?>" lang="<?php $this->text('lang') ?>" dir="<?php $this->text('dir') ?>">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="<?php $this->text('mimetype') ?>; charset=<?php $this->text('charset') ?>" />
|
||||
<?php $this->html('headlinks') ?>
|
||||
<title><?php $this->text('pagetitle') ?></title>
|
||||
<?php $this->html('csslinks') ?>
|
||||
|
||||
<!--[if lt IE 7]><script type="<?php $this->text('jsmimetype') ?>" src="<?php $this->text('stylepath') ?>/common/IEFixes.js?<?php echo $GLOBALS['wgStyleVersion'] ?>"></script>
|
||||
<meta http-equiv="imagetoolbar" content="no" /><![endif]-->
|
||||
|
||||
|
||||
<?php print Skin::makeGlobalVariablesScript( $this->data ); ?>
|
||||
|
||||
|
||||
<script type="<?php $this->text('jsmimetype') ?>" src="<?php $this->text('stylepath' ) ?>/common/wikibits.js?<?php echo $GLOBALS['wgStyleVersion'] ?>"><!-- wikibits js --></script>
|
||||
<!-- Head Scripts -->
|
||||
|
||||
<?php if($this->data['pagecss']) { ?>
|
||||
<style type="text/css"><?php $this->html('pagecss') ?></style>
|
||||
<?php }
|
||||
if($this->data['usercss']) { ?>
|
||||
<style type="text/css"><?php $this->html('usercss') ?></style>
|
||||
<?php } ?>
|
||||
|
||||
<?php $this->html('headscripts') ?>
|
||||
<?php if($this->data['jsvarurl']) { ?>
|
||||
<script type="<?php $this->text('jsmimetype') ?>" src="<?php $this->text('jsvarurl') ?>"><!-- site js --></script>
|
||||
<?php }
|
||||
if($this->data['userjs']) { ?>
|
||||
<script type="<?php $this->text('jsmimetype') ?>" src="<?php $this->text('userjs' ) ?>"></script>
|
||||
<?php }
|
||||
if($this->data['userjsprev']) { ?>
|
||||
<script type="<?php $this->text('jsmimetype') ?>"><?php $this->html('userjsprev') ?></script>
|
||||
<?php }
|
||||
if($this->data['trackbackhtml']) print $this->data['trackbackhtml']; ?>
|
||||
|
||||
<?php
|
||||
global $wgAqueductLayoutMode;
|
||||
if ($wgAqueductLayoutMode)
|
||||
{?>
|
||||
<script type="text/javascript">
|
||||
var aqExtraHeight;
|
||||
//On document.ready, begin building the grids
|
||||
jQuery(document).ready(function () {
|
||||
aqExtraHeight = jQuery('#column-content').attr('offsetHeight')
|
||||
+ parseFloat(jQuery('#column-content').css('margin-bottom').replace("px",""))
|
||||
+ parseFloat(jQuery('#column-content').css('margin-top').replace("px",""))
|
||||
+ parseFloat(jQuery('#footer').css('margin-top').replace("px",""))
|
||||
+ parseFloat(jQuery('#footer').css('margin-bottom').replace("px",""));
|
||||
var totalWidth = jQuery('#firstHeading').attr('scrollWidth');
|
||||
var totalHeight = jQuery('html').attr('scrollHeight') - aqExtraHeight - jQuery('#footer').attr('offsetHeight');
|
||||
|
||||
jQuery('#aqgrid').css('width', Math.floor(totalWidth)).css('height', Math.floor(totalHeight));
|
||||
|
||||
jQuery('#gridPresizer').css('width', Math.floor(totalWidth)).css('height','auto');
|
||||
|
||||
aqWidgetCreateRootNode(Math.floor(totalHeight), Math.floor(totalWidth));
|
||||
|
||||
var unpositionedwidgets = [];
|
||||
var wikiTextPositioned = false;
|
||||
var nopositions = true;
|
||||
if (typeof(aqWidgetList) != 'undefined')
|
||||
{
|
||||
for (n in aqWidgetList)
|
||||
{
|
||||
var w = aqWidgetList[n];
|
||||
if (w[5] == 'invisible')
|
||||
{
|
||||
var wdivid = "invisiblewidget" + n;
|
||||
jQuery('#invisibleWidgets').append('<div id="' + wdivid +'"></div>');
|
||||
new CisternWidget(wdivid,w[0],w[1],w[2],w[3],w[4],null);
|
||||
}
|
||||
else if (w[8])
|
||||
{
|
||||
if (!wikiTextPositioned)
|
||||
{
|
||||
aqAddWidgetToTree(w[5],w[6],w[7],w,true,w[9]);
|
||||
wikiTextPositioned = true;
|
||||
nopositions = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (w[5])
|
||||
{
|
||||
nopositions = false;
|
||||
aqAddWidgetToTree(w[5],w[6],w[7],w,false,w[9]);
|
||||
}
|
||||
else
|
||||
{
|
||||
unpositionedwidgets.push(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Now place the widgets where the user did not specify a position
|
||||
if (nopositions)
|
||||
unpositionedwidgets.push([null,null,null,null,null,null,null,null,true,false]);
|
||||
var newpositions = aqFindEmptyPositions(unpositionedwidgets.length);
|
||||
for (n in unpositionedwidgets)
|
||||
{
|
||||
var w = unpositionedwidgets[n];
|
||||
var pos = newpositions.shift();
|
||||
aqAddWidgetToTree(pos,'','',w,w[8],false);
|
||||
}
|
||||
aqBuildWidgetGrid();
|
||||
|
||||
});
|
||||
|
||||
jQuery(window).resize(function(){
|
||||
//The following statement will actually destroy the grid and rebuild it
|
||||
aqRemoveWidgetGrid();
|
||||
var totalWidth = jQuery('#firstHeading').attr('scrollWidth');
|
||||
var totalHeight = jQuery('html').attr('scrollHeight') - aqExtraHeight - jQuery('#footer').attr('offsetHeight');
|
||||
aqResizeWidgetGrid(Math.floor(totalHeight), Math.floor(totalWidth));
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<?php }?>
|
||||
|
||||
|
||||
</head>
|
||||
<body<?php if($this->data['body_ondblclick']) { ?> ondblclick="<?php $this->text('body_ondblclick') ?>"<?php } ?>
|
||||
<?php if($this->data['body_onload']) { ?> onload="<?php $this->text('body_onload') ?>"<?php } ?>
|
||||
class="mediawiki <?php $this->text('dir') ?> <?php $this->text('pageclass') ?> <?php $this->text('skinnameclass') ?>">
|
||||
<div id="globalWrapper">
|
||||
<div id="column-content">
|
||||
<div id="content">
|
||||
<a name="top" id="top"></a>
|
||||
<?php if($this->data['sitenotice']) { ?><div id="siteNotice"><?php $this->html('sitenotice') ?></div><?php } ?>
|
||||
<h1 id="firstHeading" class="firstHeading"><?php $this->data['displaytitle']!=""?$this->html('title'):$this->text('title') ?></h1>
|
||||
<div id="aqgrid"></div>
|
||||
<div id="gridPresizer" style='overflow:visible;visibility:hidden'></div>
|
||||
<div id="invisibleWidgets" style='display:none'></div>
|
||||
|
||||
<?php
|
||||
if ($wgAqueductLayoutMode) { ?>
|
||||
<div id="wikiTextContainer" style="display:none">
|
||||
<?php } ?>
|
||||
<div id="bodyContent">
|
||||
<h3 id="siteSub"><?php $this->msg('tagline') ?></h3>
|
||||
<div id="contentSub"><?php $this->html('subtitle') ?></div>
|
||||
<?php if($this->data['undelete']) { ?><div id="contentSub2"><?php $this->html('undelete') ?></div><?php } ?>
|
||||
<?php if($this->data['newtalk'] ) { ?><div class="usermessage"><?php $this->html('newtalk') ?></div><?php } ?>
|
||||
<?php if($this->data['showjumplinks']) { ?><div id="jump-to-nav"><?php $this->msg('jumpto') ?> <a href="#column-one"><?php $this->msg('jumptonavigation') ?></a>, <a href="#searchInput"><?php $this->msg('jumptosearch') ?></a></div><?php } ?>
|
||||
<!-- start content -->
|
||||
<?php $this->html('bodytext') ?>
|
||||
<?php if($this->data['catlinks']) { $this->html('catlinks'); } ?>
|
||||
<!-- end content -->
|
||||
<?php if($this->data['dataAfterContent']) { $this->html ('dataAfterContent'); } ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if ($wgAqueductLayoutMode) { ?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<div class="visualClear"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="column-one">
|
||||
<div id="p-cactions" class="portlet">
|
||||
<h5><?php $this->msg('views') ?></h5>
|
||||
<div class="pBody">
|
||||
<ul>
|
||||
<?php foreach($this->data['content_actions'] as $key => $tab) {
|
||||
echo '
|
||||
<li id="' . Sanitizer::escapeId( "ca-$key" ) . '"';
|
||||
if( $tab['class'] ) {
|
||||
echo ' class="'.htmlspecialchars($tab['class']).'"';
|
||||
}
|
||||
echo'><a href="'.htmlspecialchars($tab['href']).'"';
|
||||
# We don't want to give the watch tab an accesskey if the
|
||||
# page is being edited, because that conflicts with the
|
||||
# accesskey on the watch checkbox. We also don't want to
|
||||
# give the edit tab an accesskey, because that's fairly su-
|
||||
# perfluous and conflicts with an accesskey (Ctrl-E) often
|
||||
# used for editing in Safari.
|
||||
if( in_array( $action, array( 'edit', 'submit' ) )
|
||||
&& in_array( $key, array( 'edit', 'watch', 'unwatch' ))) {
|
||||
echo $skin->tooltip( "ca-$key" );
|
||||
} else {
|
||||
echo $skin->tooltipAndAccesskey( "ca-$key" );
|
||||
}
|
||||
echo '>'.htmlspecialchars($tab['text']).'</a></li>';
|
||||
} ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="portlet" id="p-personal">
|
||||
<h5><?php $this->msg('personaltools') ?></h5>
|
||||
<div class="pBody">
|
||||
<ul>
|
||||
<?php foreach($this->data['personal_urls'] as $key => $item) { ?>
|
||||
<li id="<?php echo Sanitizer::escapeId( "pt-$key" ) ?>"<?php
|
||||
if ($item['active']) { ?> class="active"<?php } ?>><a href="<?php
|
||||
echo htmlspecialchars($item['href']) ?>"<?php echo $skin->tooltipAndAccesskey('pt-'.$key) ?><?php
|
||||
if(!empty($item['class'])) { ?> class="<?php
|
||||
echo htmlspecialchars($item['class']) ?>"<?php } ?>><?php
|
||||
echo htmlspecialchars($item['text']) ?></a></li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="portlet" id="p-logo">
|
||||
<a style="background-image: url(<?php $this->text('logopath') ?>);" <?php
|
||||
?>href="<?php echo htmlspecialchars($this->data['nav_urls']['mainpage']['href'])?>"<?php
|
||||
echo $skin->tooltipAndAccesskey('p-logo') ?>></a>
|
||||
</div>
|
||||
<script type="<?php $this->text('jsmimetype') ?>"> if (window.isMSIE55) fixalpha(); </script>
|
||||
<?php
|
||||
$sidebar = $this->data['sidebar'];
|
||||
if ( !isset( $sidebar['SEARCH'] ) ) $sidebar['SEARCH'] = true;
|
||||
if ( !isset( $sidebar['TOOLBOX'] ) ) $sidebar['TOOLBOX'] = true;
|
||||
if ( !isset( $sidebar['LANGUAGES'] ) ) $sidebar['LANGUAGES'] = true;
|
||||
foreach ($sidebar as $boxName => $cont) {
|
||||
if ( $boxName == 'SEARCH' ) {
|
||||
$this->searchBox();
|
||||
} elseif ( $boxName == 'TOOLBOX' ) {
|
||||
$this->toolbox();
|
||||
} elseif ( $boxName == 'LANGUAGES' ) {
|
||||
$this->languageBox();
|
||||
} else {
|
||||
$this->customBox( $boxName, $cont );
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div><!-- end of the left (by default at least) column -->
|
||||
<div class="visualClear"></div>
|
||||
<div id="footer">
|
||||
<?php
|
||||
if($this->data['poweredbyico']) { ?>
|
||||
<div id="f-poweredbyico"><?php $this->html('poweredbyico') ?></div>
|
||||
<?php }
|
||||
if($this->data['copyrightico']) { ?>
|
||||
<div id="f-copyrightico"><?php $this->html('copyrightico') ?></div>
|
||||
<?php }
|
||||
|
||||
// Generate additional footer links
|
||||
$footerlinks = array(
|
||||
'lastmod', 'viewcount', 'numberofwatchingusers', 'credits', 'copyright',
|
||||
'privacy', 'about', 'disclaimer', 'tagline',
|
||||
);
|
||||
$validFooterLinks = array();
|
||||
foreach( $footerlinks as $aLink ) {
|
||||
if( isset( $this->data[$aLink] ) && $this->data[$aLink] ) {
|
||||
$validFooterLinks[] = $aLink;
|
||||
}
|
||||
}
|
||||
if ( count( $validFooterLinks ) > 0 ) {
|
||||
?> <ul id="f-list">
|
||||
<?php
|
||||
foreach( $validFooterLinks as $aLink ) {
|
||||
if( isset( $this->data[$aLink] ) && $this->data[$aLink] ) {
|
||||
?> <li id="<?php echo$aLink?>"><?php $this->html($aLink) ?></li>
|
||||
<?php }
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<?php }
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php $this->html('bottomscripts'); /* JS call to runBodyOnloadHook */ ?>
|
||||
<?php $this->html('reporttime') ?>
|
||||
<?php if ( $this->data['debug'] ): ?>
|
||||
<!-- Debug output:
|
||||
<?php $this->text( 'debug' ); ?>
|
||||
|
||||
-->
|
||||
<?php endif; ?>
|
||||
</body></html>
|
||||
<?php
|
||||
wfRestoreWarnings();
|
||||
} // end of execute() method
|
||||
|
||||
/*************************************************************************************************/
|
||||
function searchBox() {
|
||||
global $wgUseTwoButtonsSearchForm;
|
||||
?>
|
||||
<div id="p-search" class="portlet">
|
||||
<h5><label for="searchInput"><?php $this->msg('search') ?></label></h5>
|
||||
<div id="searchBody" class="pBody">
|
||||
<form action="<?php $this->text('wgScript') ?>" id="searchform"><div>
|
||||
<input type='hidden' name="title" value="<?php $this->text('searchtitle') ?>"/>
|
||||
<input id="searchInput" name="search" type="text"<?php echo $this->skin->tooltipAndAccesskey('search');
|
||||
if( isset( $this->data['search'] ) ) {
|
||||
?> value="<?php $this->text('search') ?>"<?php } ?> />
|
||||
<input type='submit' name="go" class="searchButton" id="searchGoButton" value="<?php $this->msg('searcharticle') ?>"<?php echo $this->skin->tooltipAndAccesskey( 'search-go' ); ?> /><?php if ($wgUseTwoButtonsSearchForm) { ?>
|
||||
<input type='submit' name="fulltext" class="searchButton" id="mw-searchButton" value="<?php $this->msg('searchbutton') ?>"<?php echo $this->skin->tooltipAndAccesskey( 'search-fulltext' ); ?> /><?php } else { ?>
|
||||
|
||||
<div><a href="<?php $this->text('searchaction') ?>" rel="search"><?php $this->msg('powersearch-legend') ?></a></div><?php } ?>
|
||||
|
||||
</div></form>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
function toolbox() {
|
||||
?>
|
||||
<div class="portlet" id="p-tb">
|
||||
<h5><?php $this->msg('toolbox') ?></h5>
|
||||
<div class="pBody">
|
||||
<ul>
|
||||
<?php
|
||||
if($this->data['notspecialpage']) { ?>
|
||||
<li id="t-whatlinkshere"><a href="<?php
|
||||
echo htmlspecialchars($this->data['nav_urls']['whatlinkshere']['href'])
|
||||
?>"<?php echo $this->skin->tooltipAndAccesskey('t-whatlinkshere') ?>><?php $this->msg('whatlinkshere') ?></a></li>
|
||||
<?php
|
||||
if( $this->data['nav_urls']['recentchangeslinked'] ) { ?>
|
||||
<li id="t-recentchangeslinked"><a href="<?php
|
||||
echo htmlspecialchars($this->data['nav_urls']['recentchangeslinked']['href'])
|
||||
?>"<?php echo $this->skin->tooltipAndAccesskey('t-recentchangeslinked') ?>><?php $this->msg('recentchangeslinked') ?></a></li>
|
||||
<?php }
|
||||
}
|
||||
if(isset($this->data['nav_urls']['trackbacklink'])) { ?>
|
||||
<li id="t-trackbacklink"><a href="<?php
|
||||
echo htmlspecialchars($this->data['nav_urls']['trackbacklink']['href'])
|
||||
?>"<?php echo $this->skin->tooltipAndAccesskey('t-trackbacklink') ?>><?php $this->msg('trackbacklink') ?></a></li>
|
||||
<?php }
|
||||
if($this->data['feeds']) { ?>
|
||||
<li id="feedlinks"><?php foreach($this->data['feeds'] as $key => $feed) {
|
||||
?><a id="<?php echo Sanitizer::escapeId( "feed-$key" ) ?>" href="<?php
|
||||
echo htmlspecialchars($feed['href']) ?>" rel="alternate" type="application/<?php echo $key ?>+xml" class="feedlink"<?php echo $this->skin->tooltipAndAccesskey('feed-'.$key) ?>><?php echo htmlspecialchars($feed['text'])?></a>
|
||||
<?php } ?></li><?php
|
||||
}
|
||||
|
||||
foreach( array('contributions', 'log', 'blockip', 'emailuser', 'upload', 'specialpages') as $special ) {
|
||||
|
||||
if($this->data['nav_urls'][$special]) {
|
||||
?><li id="t-<?php echo $special ?>"><a href="<?php echo htmlspecialchars($this->data['nav_urls'][$special]['href'])
|
||||
?>"<?php echo $this->skin->tooltipAndAccesskey('t-'.$special) ?>><?php $this->msg($special) ?></a></li>
|
||||
<?php }
|
||||
}
|
||||
|
||||
if(!empty($this->data['nav_urls']['print']['href'])) { ?>
|
||||
<li id="t-print"><a href="<?php echo htmlspecialchars($this->data['nav_urls']['print']['href'])
|
||||
?>" rel="alternate"<?php echo $this->skin->tooltipAndAccesskey('t-print') ?>><?php $this->msg('printableversion') ?></a></li><?php
|
||||
}
|
||||
|
||||
if(!empty($this->data['nav_urls']['permalink']['href'])) { ?>
|
||||
<li id="t-permalink"><a href="<?php echo htmlspecialchars($this->data['nav_urls']['permalink']['href'])
|
||||
?>"<?php echo $this->skin->tooltipAndAccesskey('t-permalink') ?>><?php $this->msg('permalink') ?></a></li><?php
|
||||
} elseif ($this->data['nav_urls']['permalink']['href'] === '') { ?>
|
||||
<li id="t-ispermalink"<?php echo $this->skin->tooltip('t-ispermalink') ?>><?php $this->msg('permalink') ?></li><?php
|
||||
}
|
||||
|
||||
wfRunHooks( 'MonoBookTemplateToolboxEnd', array( &$this ) );
|
||||
wfRunHooks( 'SkinTemplateToolboxEnd', array( &$this ) );
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
function languageBox() {
|
||||
if( $this->data['language_urls'] ) {
|
||||
?>
|
||||
<div id="p-lang" class="portlet">
|
||||
<h5><?php $this->msg('otherlanguages') ?></h5>
|
||||
<div class="pBody">
|
||||
<ul>
|
||||
<?php foreach($this->data['language_urls'] as $langlink) { ?>
|
||||
<li class="<?php echo htmlspecialchars($langlink['class'])?>"><?php
|
||||
?><a href="<?php echo htmlspecialchars($langlink['href']) ?>"><?php echo $langlink['text'] ?></a></li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
function customBox( $bar, $cont ) {
|
||||
?>
|
||||
<div class='generated-sidebar portlet' id='<?php echo Sanitizer::escapeId( "p-$bar" ) ?>'<?php echo $this->skin->tooltip('p-'.$bar) ?>>
|
||||
<h5><?php $out = wfMsg( $bar ); if (wfEmptyMsg($bar, $out)) echo $bar; else echo $out; ?></h5>
|
||||
<div class='pBody'>
|
||||
<?php if ( is_array( $cont ) ) { ?>
|
||||
<ul>
|
||||
<?php foreach($cont as $key => $val) { ?>
|
||||
<li id="<?php echo Sanitizer::escapeId($val['id']) ?>"<?php
|
||||
if ( $val['active'] ) { ?> class="active" <?php }
|
||||
?>><a href="<?php echo htmlspecialchars($val['href']) ?>"<?php echo $this->skin->tooltipAndAccesskey($val['id']) ?>><?php echo htmlspecialchars($val['text']) ?></a></li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
<?php } else {
|
||||
# allow raw HTML block to be defined by extensions
|
||||
print $cont;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
} // end of class
|
||||
|
||||
|
||||
106
aqueduct.html
Normal file
106
aqueduct.html
Normal file
@@ -0,0 +1,106 @@
|
||||
<html><body>
|
||||
|
||||
<h2><a name="AqueductDocumentation-1.2-TheAqueductextensionforMediawiki"></a>The Aqueduct extension for Mediawiki</h2>
|
||||
|
||||
<p>The Aqueduct extension for Mediawiki provides several services. The extension allows the administrator to define a mapping between wiki pages and URIs. The administrator must also specify where the data for the URIs is located and how it can be retrieved.</p>
|
||||
|
||||
<p>The Aqueduct extension allows for the creation of wikis where users visualize, analyze, discuss, and enhance semantic data. In a way, the wiki acts as a "lens" into semantic data. This semantic data typically resides outside of the wiki, and can be scattered across multiple datasources and servers. The extension does not copy any data into the wiki; instead, it dispatches requests for external semantic data to the proper server and datasource.</p>
|
||||
|
||||
<p>Because data can be scattered across multiple datasources and servers, Aqueduct introduces the concept of "RDF sources". An "RDF source" defines how the triples for a collection of data can be retrieved, and how the URIs for the data can be mapped into the wiki.</p>
|
||||
|
||||
<p>To ensure that semantic data can be located unambiguously, Aqueduct defines a mapping between the titles (or "name") of wiki pages and the URIs that they describe. Therefore, the set of possible titles must be partitioned up such that any given title is associated with no more than one URI and RDF source. This is done by associating Mediawiki namespaces with Aqueduct RDF sources. Mediawiki namespaces allow two pages with the same title to be created, as long as they are in different namespaces. By associating RDF sources with namespaces, the same title can be used to describe several URIs, as long as each URI ends up in a different namespace.</p>
|
||||
|
||||
<p>This extends the "lens" analogy -- the wiki acts as a lens into multiple sources of semantic data, and these sources are "projected" into the wiki, in a manner such that they do not overlap.</p>
|
||||
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-UnderstandingRDFSources"></a>Understanding RDF Sources</h3>
|
||||
|
||||
<p>RDF sources are a key concept in Aqueduct because all data manipulated in Aqueduct flows from an RDF source.</p>
|
||||
|
||||
<p>Aqueduct allows users to place data visualization widgets in wikis in order to visualize RDF data. Aqueduct allows different widgets to simultaneously visualize RDF data that comes from several sources. Data can reside on an external server, on the same server as the wiki, or even within the wiki itself. Aqueduct supports the following RDF sources:</p>
|
||||
<ul>
|
||||
<li>Blackbook: Blackbook is a server program that is capable of hosting large RDF data sets. Aqueduct can connect to a Blackbook 2.8 or Blackbook 3.0 server and visualize its data in the wiki. The Blackbook server can be on a different host than the one running Aqueduct. The best practice is to create multiple RDF sources per Blackbook server, one for each Blackbook datasource.</li>
|
||||
<li>ARC2: ARC2 refers to a third-party RDF processing toolkit that is integrated into Aqueduct. ARC2 allows the RDF data to be stored in the same database as the wiki pages. When an ARC2 datasource is set up and used, ARC2 will create tables in the wiki database to store the desired RDF. RDF data can be ingested through Aqueduct's "aqueductset" Mediawiki API, which becomes available upon installing Aqueduct. Multiple ARC2 datasources can share the same database tables or use different database tables, depending on the "datastore name" setting.</li>
|
||||
|
||||
<li>Embedded: This refers to the practice of using special Mediawiki markup to store the representation of RDF data within the wiki itself. When a query is performed, the appropriate wiki pages will be read and the data will be collected from them. No data is stored in any database, aside from being stored as part of the wiki page text. Note that the Siphon product (included with Aqueduct) performs a similar function, except data is mirrored into Blackbook so it can be queried.</li>
|
||||
<li>Test: For testing only. A small amount of test data is built into Aqueduct, and it cannot be changed. Selecting the Test RDF Source will cause this data to be read.</li>
|
||||
<li>Memcached: For debugging purposes only.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-ConfiguringtheAqueductextension"></a>Configuring the Aqueduct extension</h3>
|
||||
|
||||
<p>To configure the Aqueduct extension, you must create RDF sources for the data that will be made available through the wiki.</p>
|
||||
|
||||
<p>To configure an RDF source, you must fill the following columns:</p>
|
||||
<ul>
|
||||
<li>Wiki namespace ID: Mediawiki internally uses ID numbers to define namespaces. Because every RDF source is associated with a wiki namespace, you must choose a different namespace ID for each RDF source. The namespace IDs that you choose cannot already be in use. Namespace IDs must be even numbers. For a typical wiki that doesn't define any custom namespaces other than the ones associated with Semantic Mediawiki and Semantic Forms, a safe strategy is to use IDs starting with 120, such that the IDs are 120, 122, 124, 126... Once a wiki namespace ID is configured, it must not be changed if any wiki pages were created in the namespace. Assigning a namespace ID of 0 will associate the RDF source with the wiki's main namespace (which contains all pages which are not in any other namespace.)</li>
|
||||
<li>Wiki namespace: This is a word of your choosing that names the RDF source and namespace that you are creating. It can be changed at a later date, but doing so is not recommended because doing so can confuse users.</li>
|
||||
<li>Datastore URI prefix: This should be the longest common prefix that URIs in this RDF source have, as long as each URI has at least 1 character after removing the prefix. If URIs in a data store have several possible prefixes, consider creating a different RDF source for every prefix. Defining a good URI prefix is strongly recommended, because Aqueduct names page titles by stripping the prefix from their associated URIs.</li>
|
||||
<li>Datastore Type:
|
||||
<ul>
|
||||
<li>If the data is stored in Blackbook, enter BB28 or BB30, depending on the version</li>
|
||||
|
||||
<li>If the data is stored in the internal ARC2 triple store, select Arc2</li>
|
||||
<li>If you are using the Embedded RDF source, Memcached RDF source, or Test RDF source (explained later in this document), select the appropriate option</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Datastore Name:
|
||||
<ul>
|
||||
<li>If the data is stored in Blackbook, this is only used if you are going to persist changes back to the datasource using the Aqueduct API (not Siphon). Enter the Blackbook datasource name that the changes will be written to.</li>
|
||||
<li>If the data is stored in the internal ARC2 triple store, enter a short alphanumeric string to identify the database tables where the data will be stored. ARC2 will automatically create database tables to store RDF within the wiki database. RDF sources with different datastore names will be backed by different database tables.</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
<li>Datastore Location: If the RDF source is Blackbook, enter the base URI for the Blackbook web service here.</li>
|
||||
<li>Datastore certificate path: If the RDF source is Blackbook, enter the pathname of the certificate (PEM) file containing the server certificate that will be used to authenticate the Blackbook web service connection. Note that this is different from the client certificate -- the client certificate will be sent from the user's browser when needed.</li>
|
||||
<li>Certificate password: If the RDF source is Blackbook, this is the password that was used to encrypt the certificate file mentioned in "Datastore certificate path".</li>
|
||||
<li>Title initial lowercase: Here, specify if the first letter of the URI fragment following the URI prefix should be lowercase by default. In other words, after stripping the URI prefix from all the URIs defined in the datasource, check the cases of the first letters of the URI fragments that remain. If the majority of the URI fragments start with an uppercase letter, enter 0. If the majority of the URI fragments start with a lowercase letter, enter 1. Entering an incorrect value here will not prevent you from using Aqueduct, but the resulting titles will contain visible control characters to compensate for the fact that Mediawiki titles must all begin with uppercase letters.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-MoreonthetestRDFsource"></a>More on the test RDF source</h3>
|
||||
|
||||
<p>The test RDF source allows you to test Aqueduct without being connected to a Blackbook data source. SSL and browser certificates are not required. This helps ensure that the widgets are working as intended.</p>
|
||||
|
||||
<p>The following URIs are defined in the test RDF source:</p>
|
||||
<ul>
|
||||
<li>uri:citydata:Chicago</li>
|
||||
<li>uri:citydata:Gary</li>
|
||||
|
||||
<li>uri:citydata:Skokie</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>To enable the test RDF source for a namespace, create a datastore with a type of Test. The other settings can be set however you want; however, it will be easiest to access the test data if you set them as follows:</p>
|
||||
<ul>
|
||||
<li>Wiki Namespace Id: <next free namespace ID></li>
|
||||
<li>Wiki Namespace: <namespace of your choosing></li>
|
||||
|
||||
<li>Datastore URI prefix: uri:citydata:</li>
|
||||
<li>Datastore Type: Test</li>
|
||||
<li>Title initial lowercase: 0</li>
|
||||
<li>Other settings: Blank</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>If you used the above settings, you will be able to put widgets on pages called "Chicago", "Gary", and "Skokie" (in the namespace that you created).</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-TheAqueductwidgets"></a>The Aqueduct widgets</h3>
|
||||
|
||||
<p>Once you have the RDF sources set up for the Aqueduct extension, you can place Aqueduct widgets on wiki pages. Aqueduct widgets are potentially interactive controls that allow the user to visualize the RDF associated with a wiki page.</p>
|
||||
|
||||
<p>To place a widget on the page, insert the name of the widget surrounded by angle brackets. For example, entering <aqRawWidget> or <aqTableViewWidget> will show the Raw RDF or the Table widget. Each widget will visualize the same data in a different way.</p>
|
||||
|
||||
<p>Widgets have no parameters and cannot be configured. Each widget automatically displays the data for the URI associated with the wiki page where it was placed.</p>
|
||||
|
||||
<p>The following widgets currently exist:</p>
|
||||
<ul>
|
||||
<li>aqRawWidget - The Raw RDF widget is useful for troubleshooting. It shows the user the RDF triples returned from the query with minimal processing. This widget allows the user to select from two views -- the Table view shows a table listing the RDF statements, and the JSON view shows the same information in an RDF-JSON data structure.</li>
|
||||
<li>aqTableViewWidget - The Table widget shows a table with one row for each entity and one column for each property (predicate) describing the entity.</li>
|
||||
<li>aqNetworkViewWidget - The Network view widget shows a 3-D Google Earth globe with one pushpin for each entity that had location data associated with it. The predicates <a href="http://www.w3.org/2003/01/geo/wgs84_pos#long">http://www.w3.org/2003/01/geo/wgs84_pos#long</a> and <a href="http://www.w3.org/2003/01/geo/wgs84_pos#lat">http://www.w3.org/2003/01/geo/wgs84_pos#lat</a> must be present in the data for a pushpin to be display. Arcs are drawn between pushpins when the object URI starts with urn: or http:// , and the destination object was found in the result set.</li>
|
||||
|
||||
<li>aqNetworkViewWidget2D - Same as the Google Earth widget, but it uses Google Maps instead of Google Earth (so no plugin is required). Arcs between pushpins are not supported.</li>
|
||||
</ul>
|
||||
</body></html>
|
||||
360
aqueductadvanced.html
Normal file
360
aqueductadvanced.html
Normal file
@@ -0,0 +1,360 @@
|
||||
<html><body>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Includingwidgetsinanotherpage%26nbsp%3B"></a>Including widgets in another page </h3>
|
||||
|
||||
<p>Note that the above setup only allows the widgets to display data associated with the page where they are placed. This means that all widgets on the page will be displaying the same data. Because this is not always desirable, the user can insert the aqIncludeWidgets tag, which includes widgets from other pages (which will be display different data.)</p>
|
||||
|
||||
<p>To use this tag, specify the title of the page with the widgets that you want to include like this: <aqIncludeWidgets>Namespace:PageTitle</aqIncludeWidgets>. All the widgets on the specified page will be inserted in place of the inclusion tag. They will be rendered exactly as they appeared in the page that is being included, with the same data that would have appeared when directly navigating to that page.</p>
|
||||
|
||||
<p>The aqIncludeWidgets tag can be used recursively to build "building blocks" that will include several widgets from multiple sources. The aqIncludeWidgets tag will behave in the same way when used recurisvely -- whatever widgets appear on the included page will also appear in the page that uses the tag, regardless of where the widgets originally came from.</p>
|
||||
|
||||
<p>Mediawiki templating (using the {} curly braces) will not behave as expected because the widget tags will be considered part of the including page, and they won't use the data of the page where they appeared. However, using templates can still be useful because commonly used collections widget tags can be "aliased" as a template to make them easier to type.</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Combiningdatafrommultiplesources"></a>Combining data from multiple sources</h3>
|
||||
|
||||
<p>The feature above allows you to display several widgets on a page with different data in each, but they still don't allow you to combine data from multiple entities or queries into one widget.</p>
|
||||
|
||||
<p>To do this, use the aqAddData tag, which takes all RDF data from the specified entity and causes it to be "merged" with the current entity. Although the data is not modified in Blackbook, this feature causes Aqueduct to treat the two entities as one. As far as Aqueduct is concerned, the specified data becomes a part of the entity corresponding to the page where you used the aqAddData tag.</p>
|
||||
|
||||
<p>To use the aqAddData tag, use the following syntax: <aqAddData>Namespace:PageTitle</aqAddData> . Note that the specified wiki page need not exist, as long as there is semantic data associated with the page title. The aqAddData tag can also be used recursively.</p>
|
||||
|
||||
<p>Note that, unlike with the aqIncludeWidgets tag, the aqAddData tag also affects the behavior of the API, and API consumers will see the merged data. Also note that aqAddData can be used to include queries (advanced RDF source pages) as well as simple RDF entities.</p>
|
||||
|
||||
<p>There are two main use cases for the aqAddData tag:<br/>
|
||||
1. You can build a "virtual entity" by merging the data from several other entities together and treating it as one. To do this, create a page with several aqAddData tags on it. The page should be outside of an Aqueduct namespace (there shouldn't be any semantic data associated with the page until you add the aqAddData tags.) This "virtual entity" can then be used in the same way as any other entity -- you can put widgets on it, include the widgets in other pages by using aqIncludeWidgets, and even recursively merge the virtual entity into other pages by using the aqAddData tag again.</p>
|
||||
|
||||
<p>2. You can "augment" the data for an entity by including other data that you know is relevant to it. To do this, browse to the page for an entity and use aqAddData to include the data that is deemed relevant. At this point, any other pages that use aqIncludeWidgets or aqAddData to reference the entity will also see the data that you associated.</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Embeddingdatainthewiki%28wikiasadatasource%29"></a>Embedding data in the wiki (wiki as a data source)</h3>
|
||||
|
||||
<p>It is often useful to store RDF data directly in the wiki, allowing the wiki to act as a both a datasource and a data display system.</p>
|
||||
|
||||
<p>Aqueduct provides functionality allowing the user to embed RDF triples in a special namespace, with wiki pages representing entities (in the same way that page represent entities when querying other datasource). When Aqueduct needs to materialize an entity, it scans the corresponding page for triples and returns them.</p>
|
||||
|
||||
<p>This functionality is distinct from any Semantic Mediawiki support Siphon provides. Embedding triples with Semantic Mediawiki requires the user to have a copy of Semantic Mediawiki and a Blackbook instance to receive the triples. In this case, Aqueduct queries Blackbook for the desired entities, instead of reading the wiki pages.</p>
|
||||
|
||||
<p>Using the Semantic Mediawiki and Siphon approach has the advantage of enabling advanced queries and the use of any algorithm that Blackbook supports. The Embedded Data support being discussed in this section does not support algorithms or advanced queries.</p>
|
||||
|
||||
<p>The advantage of the Embedded Data support discussed here is that neither Semantic Mediawiki or Blackbook is required. Also, the semantic data is available instantly, without waiting for Siphon to process it. </p>
|
||||
|
||||
<p>To embed triples in the wiki, create an RDF source with a datastore type of "Embedded" and choose a datastore URI prefix. Aqueduct will then allow you to embed triples in this namespace. The subject of the triples are implied by the datastore URI prefix and the page title where the triples are placed, while the predicate and object are specified explicitly.</p>
|
||||
|
||||
<h4><a name="AqueductDocumentation-1.2-Basictripleembedding"></a>Basic triple embedding</h4>
|
||||
|
||||
<p>To embed a triple into a wiki page in a namespace that was set up for triple embedding, use the following syntax:</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java">{{#triple:predicateuri|object|objecttype}}</pre>
|
||||
</div></div>
|
||||
<p>"predicate" is the predicate URI for the embedded triple. "objecttype" is "literal" or "uri". "object" is the object of the embedded triple.<br/>
|
||||
|
||||
You can also create templates (or parameterized templates) that call the "triple" tag. When the user embeds this template into their wiki page, it will add the triple(s) present in the template. This allows you to define your own syntax that users can use to embed triples into wiki pages. Because the default syntax is non-intuitive, creating customized triple templates is the way that this feature was intended to be used.</p>
|
||||
|
||||
<h4><a name="AqueductDocumentation-1.2-Advancedtripleembedding"></a>Advanced triple embedding</h4>
|
||||
|
||||
<p>It is also possible to embed a triple on a page that doesn't correspond to the URI of the triple. This allows you to have a single wiki page that contains triples that refer to different entities, possibly making maintenance of the data easier.</p>
|
||||
|
||||
<p>For this to work, your URIs must be constructed as follows:</p>
|
||||
<ol>
|
||||
<li>All of the URIs should contain a "common prefix", followed by a hash mark, and then a suffix that distinguishes them.</li>
|
||||
<li>The URIs should only have a single hash mark each.</li>
|
||||
|
||||
<li>The URIs should be associated with a basic RDF source of the "embedded" type, where the "Datasource URI prefix" some prefix of the "common prefix".</li>
|
||||
<li>Triples should be stored on a wiki page in the appropriate namespace, with the title of the page constructed so the page's URI equals the "common prefix". This page will be called the "base page".</li>
|
||||
<li>Triples for each subject can be viewed on "fragment pages", which have wiki titles that correspond to the URIs of the subjects. Note that because hash marks are translated into backslashes () when constructing wiki title, all fragment pages will have a backslash somewhere in the title.</li>
|
||||
<li>Triples can also be embedded on the fragment pages themselves. Triples from the base page and triples from the fragment pages will be merged when retrieving data for the fragment pages.</li>
|
||||
<li>The "Search for Fragments" parameter must be set to 1 in the configuration page. Otherwise, the base page will not be checked when viewing the fragment page.</li>
|
||||
</ol>
|
||||
|
||||
<p>The syntax for advanced triple embedding is as follows:</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java">{{#triple:predicateuri|object|objecttype|fragment}}</pre>
|
||||
</div></div>
|
||||
<p>Where "fragment" matches everything that comes after the hash mark in the URI that is to be represented. (Note that this syntax should only be used on the base page, and the basic triple embedding syntax should be used on the fragment pages.</p>
|
||||
|
||||
<p>An example:</p>
|
||||
|
||||
<p>Create an RDF source with settings: name "EmbedTest", URI prefix "uri:embedded:", type "Embedded", search for fragments "1", title initial lowercase "0".<br/>
|
||||
Create a page called "EmbedTest:People". Add</p>
|
||||
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java">{{#triple:uri:embedtest:firstname|Jeff|literal|jeff}}</pre>
|
||||
</div></div>
|
||||
<p>Create a page called "EmbedTest:People\jeff". Put a table widget on the page. The "firstname" triple created on the base page will appear.</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-AdvancedRDFsources%26nbsp%3B"></a>Advanced RDF sources </h3>
|
||||
|
||||
<p>You can also defined "Advanced RDF sources" and associate them with Mediawiki namespaces. This allows you to create wiki pages that are associated with the results of more complex queries or algorithm executions.</p>
|
||||
|
||||
<p>To configure an Advanced RDF source, you must fill in the following columns:</p>
|
||||
|
||||
<ul>
|
||||
<li>New Namespace ID: An unused namespace ID, using the same naming convention as above</li>
|
||||
<li>Associated namespace: A string that must match a "Wiki Namespace" entry in the other configuration table. This tells Aqueduct where the advanced query should be run. Also, the Datastore URI prefix of the associated namespace will be used when a paramaterized query is performed and the Use URI as Query Parameter option is set.</li>
|
||||
<li>Query Tag: A string that will be used to generate the namespace that is associated with this RDF source. The new namespace name will be the Associated namespace name, followed by an underscore, followed by the query tag.</li>
|
||||
<li>Query Type: This is a datasource-dependent property specifying what kind of query should be performed. The legal value for Blackbook is ExecuteAlgorithm</li>
|
||||
<li>Algorithm Name: This is a datasource-dependent property specifying which query should be performed. Legal values for Blackbook are LuceneKeyword, SparqlConstructQuery, SparqlDescribeQuery, SparqlSelectQuery</li>
|
||||
<li>Datasource Name: If an algorithm needs the name of a datasource to execute, the specified datasource is used.</li>
|
||||
|
||||
<li>Use URI as Query Parameter: When a parameterized query is performed, put 1 here to treat the parameter as a URI and 0 to treat the parameter as a literal.</li>
|
||||
<li>Query Text: Put the text for the SPARQL query or the keyword query here. Parameter placeholders can be placed here (see below). As a convenience, if this is left blank, the title of the page (without the namespace) will be inserted at runtime.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-MoreonnamespacesandRDFsources%26nbsp%3B"></a>More on namespaces and RDF sources </h3>
|
||||
|
||||
<p>Mediawiki internally uses the Namespace ID of a page when storing pages in the database, but links to pages (and other cached information) uses the namespace name. For this reason, it is important that once pages have been created within a particular namespace, the ID of that namespace continues to refer to the same namespace name until all pages in the namespace have been deleted.</p>
|
||||
|
||||
<p>When you define a namespace as a basic or advanced RDF source, Aqueduct will automatically set up the corresponding Mediawiki namespace so wiki pages can be named. If you remove the basic or advanced RDF source at a later date, and if the RDF source already contains pages, Aqueduct will maintain a memory of the namespace, and continue to maintain the namespace even though it no longer corresponds to an RDF source, in order to prevent previously created pages from becoming accessible.</p>
|
||||
|
||||
<p>For this reason, if you create a namespace with a particular namespace ID or name, and later delete the namespace after creating pages in it, Aqueduct will no longer allow you to create another RDF source with the same namespace ID or name, unless BOTH the namespace ID and name match the previous ones. </p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Parameterizedqueries%26nbsp%3B"></a>Parameterized queries </h3>
|
||||
|
||||
<p>The double hash mark (##) is used as a placeholder for a parameter in the "query text" for an advanced RDF source. This allows you to define an entire namespace of queries, where each page represents one value that the parameter could take on.</p>
|
||||
|
||||
<p>If "Use URI as Query Parameter" is set to 0, the placeholder is replacedwith the title of the page (unescaped, and minus the namespace). If it's set to 1, the title is converted to a URI (for this purpose, it is assumed to be in the Associated Namespace of the Advanced RDF Source), and then the URI is used instead of the placeholder.</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Manuallyspecifyinginlinequeriesforwidgets"></a>Manually specifying inline queries for widgets</h3>
|
||||
|
||||
<p>It is sometimes useful to explicitly specify SPARQL queries (or similar queries) on the same page where the query will be used, instead of specifying them in the advanced namespace configuration. Aqueduct has an <aqAddQuery> tag that allows this.</p>
|
||||
|
||||
<p>A query added with the <aqAddQuery> tag has several characteristics:</p>
|
||||
<ol>
|
||||
<li>In the tag's parameters, the user enters the same information that would be entered when configuring an advanced RDF source. This causes the current page to function as if it was part of an advanced RDF namespace.</li>
|
||||
<li>If the page is already part of a basic or advanced RDF source, the results of the query will be merged with the page's other data, in the same way that the aqAddData merges triples.</li>
|
||||
<li>If one page draws data from an aqAddQuery tag, the aqAddData tag can include the resulting data from another page. In short, the aqAddData tag still works as expected.</li>
|
||||
<li>If the aqAddQuery page is used in a template, the query will only be performed after the template is expanded, allowing you to create templates that represent commonly-used queries.</li>
|
||||
|
||||
<li>A parameterized query can still be performed when the query is defined with the aqAddQuery tag. For the purposes of the query, Aqueduct acts as if a new implicit advanced RDF namespace has been created, and the page being rendered is part of this implicit namespace. The page name can then be used to fill in a query parameter.</li>
|
||||
</ol>
|
||||
|
||||
|
||||
<p>The aqAddQuery tag has the following parameters. All parameters should be specified:</p>
|
||||
<ul>
|
||||
<li>namespace: Corresponds to the "Associated namespace" of an advanced RDF source.</li>
|
||||
<li>type: Corresponds to the "Query Type" of an advanced RDF source.</li>
|
||||
<li>datasource: Corresponds to the "Datasource Name" of an advanced RDF source.</li>
|
||||
|
||||
<li>uriasparam: Corresponds to the "Use URI as Query Parameter" of an advanced RDF source.</li>
|
||||
<li>algorithm: Corresponds to the "Algorithm Name" of an advanced RDF source.</li>
|
||||
<li>The query itself should be put inside the <aqAddQuery></aqAddQuery> tags. This corresponds to the "Query Text" of an advanced RDF source.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-AqueductPageAutoPopulation"></a>Aqueduct Page Auto-Population</h3>
|
||||
|
||||
<p>When following links to wiki pages that have a known mapping to a URI but do not yet exist, it is useful to be able to view the data for the URI without having to create a page with an Aqueduct widget on it every time. For this purpose, Aqueduct provides an auto-population utility.</p>
|
||||
|
||||
<p>This utility automatically activates if a link is followed to a wiki page that both does not exist and resides in a namespace configured through Aqueduct. If these two conditions are met, the utility searches for a Mediawiki template page to use to auto-populate the page. This template is chosen through a specific naming convention. There are two ways to configure auto-population: generically and specifically. If the page already exists, or if the page is in a namespace that is not configured by Aqueduct, then Mediawiki continues normally.</p>
|
||||
|
||||
<p>The generic configuration will be used to auto-populate any page that is created in an Aqueduct namespace. To configure this, a Mediawiki template must be created with the name "Template:Namespace", where "Namespace" is the namespace name you wish to auto-populate. Afterwards, any page created that has the name "Namespace:Page_Title", will be prepopulated with the contents of "Template:Namespace".</p>
|
||||
|
||||
<p>The specific configuration refers to the RDF type of the uri which a page maps to. It will be used to auto-populate any page created in an Aqueduct namespace that matches a given RDF type. To configure this, a Mediawiki template must be created with the name "Template:Namespace:Entity", where "Namespace" is the namespace name and "Entity" is the RDF type of the pages you wish to prepopulate. Multiple specific configurations can be created for multiple RDF entities within a single namespace.</p>
|
||||
|
||||
<p>If both a generic and a specific configuration exist for a namespace, then the specific configuration takes priority, but only when the RDF type matches. If only specific configurations exist for a namespace, then any page not matching a configuration will be treated as a normal Mediawiki page.</p>
|
||||
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Gridlayoutmode"></a>Grid layout mode</h4>
|
||||
|
||||
<p>By default, Aqueduct does not affect the layout of ordinary wiki pages. Widgets appear on wiki pages wherever the corresponding tags are placed. Optionally, the system administrator can enable grid layout mode, in order to change the page layout.</p>
|
||||
|
||||
|
||||
<p>When Aqueduct is switched to grid mode, all wiki pages are laid out in a "window pane" mode, similar to how Visual Studio or Eclipse display multiple views inside a single window. The screen is divided into up to 5 panes -- center, west, east, north, and south. These panes can be further subdivided in order to display any number of panes on the screen. Each pane will display exactly one widget, except for the pane that displays the ordinary wikitext. In grid mode, the location of the widget tags within the wikitext becomes irrelevant, because widgets are removed from the normal flow of wikitext and placed into their own grid panes.</p>
|
||||
|
||||
<p>To enable grid mode, you must perform the following steps:</p>
|
||||
<ol>
|
||||
<li>Copy or link GridBook.php from the AqueductExtension directory to the wiki's "skins" folder.</li>
|
||||
<li>Edit LocalSettings.php and set $wgDefaultSkin = 'gridbook'</li>
|
||||
|
||||
</ol>
|
||||
|
||||
|
||||
<p>After following these steps, every page in the wiki will switch to the grid mode.</p>
|
||||
|
||||
<p>If no further change are made, Aqueduct will automatically choose grid panes and place the widgets and wikitext inside them. This will not be desirable in most cases, and most users will want to manually specify the location and size of the widget panes. The following parameter can be passed to any widget, in order to influence how the widget is rendered:</p>
|
||||
<ul>
|
||||
<li>position: This parameter specifies which grid pane the widget will be drawn in. Valid entries include "north", "south", "west", "east", and "center". To subdivide a grid pane and create a complex layout, specify a path of panes. For example, "north-east" will subdivide the north pane and place the widget in the east subdivision. "center-north-west" will perform multiple subdivisions. Certain combinations on widget positions are illegal and will cause page views to fail with an error if attempted. For example, if one widget is set to "west" and the other is set to "north", the page will fail because this would leave a gap in the grid. However, adding a third widget with a position of "center" will allow the page to load, because the entire screen will be filled with grid panes. The same restrictions apply to subdivided grids</li>
|
||||
<li>height and width: This parameter specifies the preferred height or width of the widget. The following entries are possible:
|
||||
<ul>
|
||||
<li>(blank or omitted): The height or width of this widget is not important. This widget will receive whatever space is left after displaying the other widgets.</li>
|
||||
|
||||
<li>"fit": The height or width of this widget is dynamically determined by measuring the size of the content that the widget contains, causing the widget to "auto-size" to fit its contents. Note that with some widgets, the height and width are dependent on each other (for example, reducing the width will cause word-wrap which increases the height). With such widgets, it is recommended that either the height or the width be set to a fixed pixel size, to avoid unexpected results.</li>
|
||||
<li>(a number): The height or width of this widget is fixed to the specified number of pixels. Note that the dividers between panes will cause the actual size of the pane to be larger than the number entered here. Also, if it is impossible to accommodate all widgets using the provided sizes, the actual size may be less than specified.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>resizable: Set this to "true" to allow the pane to be resized by the user after the grid has displayed. Note that setting this property for the center pane has no effect, because the center pane has no resizing bars. The four resizing bars on a standard grid view belong to the north, south, west, and east panes.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>On pages where widgets are displayed, the position of the wikitext pane must also be specified. To specify this, add the <aqWikiText/> widget to the page, and then specify the position and size of the widget as normally done. Only one <aqWikiText/> widget may be added to a page at once, and this widget has no effect when the grid layout mode is turned off.</p>
|
||||
|
||||
|
||||
<p>When using the grid layout mode, watch out for the following:</p>
|
||||
<ul>
|
||||
<li>If a widget's design is incompatible with the grid layout mode, the content of the widget might not resize to fit the pane that contains it.</li>
|
||||
<li>If pane resizing is enabled ("resizable" is set to "true"), unexpected results may occur when using some widgets when the user resizes the pane. Ensure proper functionality in all scenarios before deploying a page where resizing is enabled.</li>
|
||||
<li>If the user's window is too small to accommodate all of the panes on the page, an alert box will appear notifying the user that some widgets or data may not be visible. This normally happens if panes are nested too deeply.</li>
|
||||
<li>The grid layout mode may not work properly when using Internet Explorer. It has only been tested with Firefox 3.</li>
|
||||
|
||||
<li>If the browser window is resized while a grid layout is displayed, the grid will resize along with the browser window, but many errors will appear in the browser's error console. These errors can be ignored. The user will not normally see these errors if they are not using a debugging plugin in their browser.</li>
|
||||
</ul>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-CustomizingAqueductpages%26nbsp%3B"></a>Customizing Aqueduct pages </h3>
|
||||
|
||||
<p>Aqueduct has several features that allow users to embed custom widgets in pages or add custom Javascript to pages. This can be used to create new and customized views of data, or to add Javascript functionality that is not associated with a particular widget.</p>
|
||||
|
||||
<p><em>Allowing use of these functions may be a security risk.</em> These features are disabled by default because malicious users are allowed to use them, which allow arbitrary HTML and Javascript to be injected into pages that ordinary users see, potentially allowing passwords or other information to be stolen. (When these features are disabled, Aqueduct is designed to foil such attacks.)</p>
|
||||
|
||||
<p>To allow the use of the aqLayoutWidget tag, set the $wgEnableLayoutWidgets = TRUE; configuration option in LocalSettings.php.</p>
|
||||
|
||||
<p>To allow the use of custom headers and scripts, set the $wgEnableCustomScripts = TRUE; configuration option in LocalSettings.php.</p>
|
||||
|
||||
<h4><a name="AqueductDocumentation-1.2-Customdatalayouts"></a>Custom data layouts</h4>
|
||||
|
||||
<p>Custom data layouts allow users to display RDF data in their own format, without using any of the built-in widgets (such as the table widget or network view widget). This essentially has the effect of creating a custom widget, although creating a custom layout affords less functionality than writing a full-fledged widget.</p>
|
||||
|
||||
<p>Using a custom data layout is a two-step process. First, add a aqLayout tag which contains the layout definition. Then, add a aqLayoutWidget tag to actually construct a widget that uses that layout definition to display the data. Layout definitions do not specify the data to be displayed (this is specified in the usual way) -- they only specify how to display it.</p>
|
||||
|
||||
<p>It is recommended that the aqLayout and aqLayoutWidget tags be used in pairs, and that they be placed inside a Mediawiki template. This allows users to easily insert the custom widget onto pages as if it was an ordinary widget. Because the aqLayoutWidget tag automatically uses the layout from the last aqLayout tag that was included, it is possible to put the aqLayout and aqLayoutWidget tags in different places, and then use Mediawiki templates or widget inclusion to ensure that the aqLayoutWidget tag is processed after the corresponding aqLayout tag. However, this usage is confusing.</p>
|
||||
|
||||
<h4><a name="AqueductDocumentation-1.2-Thecustomdatalayouttemplatinglanguage"></a>The custom data layout templating language</h4>
|
||||
|
||||
<p>Aqueduct data layouts are written in the jtemplates language. Documentation on the language can be found here: <a href="http://jtemplates.tpython.com/">http://jtemplates.tpython.com/</a></p>
|
||||
|
||||
<p>Templates are written by interspersing HTML with templating directives. Most templating directives either (1) cause the HTML parser to "loop" and repeat an element for each record, or (2) insert the value of a field in place of the directive.</p>
|
||||
|
||||
<p>The following directives will be useful to the template author:</p>
|
||||
|
||||
<p>Begin a foreach loop, looping through each result entity (subject).</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java">{#foreach $T as record}</pre>
|
||||
</div></div>
|
||||
<p>End the foreach loop</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java">{#/<span class="code-keyword">for</span>}</pre>
|
||||
|
||||
</div></div>
|
||||
<p>Insert an href tag which causes a link to the current entity to be created (note: jtemplates incorrectly htmlencodes the link, meaning that the link will not work if your wiki URL contains an ampersand for some reason.)</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java"><a href='{$T.record.mylink}'></pre>
|
||||
</div></div>
|
||||
<p>Inserts the wiki title of the current entity</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java">{$T.record.myvalue}</pre>
|
||||
</div></div>
|
||||
<p>Inserts object that the current entity has for predicate "uri:mypredicate"</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java">{$T.record['uri:mypredicate'].value}</pre>
|
||||
|
||||
</div></div>
|
||||
<p>Inserts a link to the wiki page for the current entity's object for predicate "uri:mypredicate" (this only makes sense if the object is a uri.)</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java"><a href='{$T.record['uri:mypredicate'].value}'></pre>
|
||||
</div></div>
|
||||
<p>If the desired predicate has multiple values, you should always use the following looping forms to ensure that the expected results are seen:</p>
|
||||
|
||||
<p>Begins looping through all values for predicate "uri:mypredicate" for the current entity.</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java">{#foreach $T.record['uri:cityschema:HasNeighbor'].all as n}</pre>
|
||||
</div></div>
|
||||
<p>Inserts the wiki link or object value for the current object when looping through predicate values</p>
|
||||
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java"><a href='{$T.n.link}'>
|
||||
{$T.n.value}</pre>
|
||||
</div></div>
|
||||
|
||||
<h4><a name="AqueductDocumentation-1.2-Exampleofacustomdatalayouttemplate"></a>Example of a custom data layout template</h4>
|
||||
|
||||
<p>The following example applies a custom layout to data from the built-in Test RDF source that was described previously.</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java"><aqLayout>
|
||||
<strong>CITY INFORMATION LIST </strong>
|
||||
|
||||
<ol>
|
||||
{#foreach $T as record}
|
||||
<li>
|
||||
<ul>
|
||||
<li>
|
||||
City name: <a href='{$T.record.mylink}'>{$T.record.myvalue}</a>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
Population: {$T.record['uri:cityschema:Population'].value}
|
||||
</li>
|
||||
<li>
|
||||
List of neighbors:
|
||||
<ol>
|
||||
|
||||
{#foreach $T.record['uri:cityschema:HasNeighbor'].all as n}
|
||||
<li><a href='{$T.n.link}'>{$T.n.value}</a></li>
|
||||
{#/<span class="code-keyword">for</span>}
|
||||
</ol>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
{#/<span class="code-keyword">for</span>}
|
||||
</ol>
|
||||
</aqLayout>
|
||||
<aqLayoutWidget/></pre>
|
||||
</div></div>
|
||||
|
||||
<h4><a name="AqueductDocumentation-1.2-Customheaders"></a>Custom headers</h4>
|
||||
|
||||
<p>The aqAddHeader tag allows users to include arbitrary Javascript files in pages. The Javascript file will be included as in "script src" on the top of the tag. This can be used to include libraries that Javascript code embedded in custom layouts will call.</p>
|
||||
|
||||
|
||||
<p>To include a custom header, add a tag like this:</p>
|
||||
|
||||
<p><aqAddHeader><a href="http://host/file.js">http://host/file.js</a></aqAddHeader> </p>
|
||||
|
||||
<h4><a name="AqueductDocumentation-1.2-Customscripts"></a>Custom scripts</h4>
|
||||
|
||||
<p>The aqAddScript tag is similar to the aqAddHeader tag, but the Javascript is added literally instead of being included from another file. The script will be placed in the head of the HTML file.</p>
|
||||
|
||||
<p>To include a custom script, add a tag like this:</p>
|
||||
|
||||
<p><aqAddScript></p>
|
||||
|
||||
<p>alert('hello'); </p>
|
||||
|
||||
<p></aqAddScript></p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-TheBlackbookMemcachedcache"></a>The Blackbook Memcached cache</h3>
|
||||
|
||||
<p>Sometimes, when Blackbook as an RDF source, it is desirable to cache the results of Blackbook queries in a faster database to improve performance. Aqueduct supports the use of Memcached, a 3rd-party caching server, to cache the results of these queries. All queries will be cached if this feature is enabled (basic and advanced operations.)</p>
|
||||
|
||||
<p>To enable this caching:</p>
|
||||
|
||||
<p>1. Install the memcached, zlib1g (for compression), and php5-memcache packages.</p>
|
||||
|
||||
<p>2. Restart your webserver to finalize the installation of the php memcache class.</p>
|
||||
|
||||
<p>3. Place these three configuration lines in the LocalSettings.php file:</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java">$aqMemcacheHost = 'localhost';
|
||||
$aqMemcachePort = '11211';
|
||||
$aqMemcacheExpirationTime = 600;</pre>
|
||||
</div></div>
|
||||
<p>The third line controls how long a key sits in the cache before expiring. The value is in seconds and cannot be over 30 days. If the value IS over 30 days, memcached will treat it as a Unix timestamp.</p>
|
||||
|
||||
<p><em>The risks of this caching should be carefully considered before enabling it.</em> Using this caching might introduce the following issues:</p>
|
||||
|
||||
<ul>
|
||||
<li>If Siphon or the Set API is used to modify the data in Blackbook or add new data to Blackbook, the data in the cache will become out of date, and inaccurate results will be returned. The same problem will occur if the Blackbook data is being modified by other means.</li>
|
||||
<li>If users have different security roles (defined by their SSL certificates), users who have one role will be able to see data from users of other roles, because the first user to access the data will cache it, and subsequent users will see the cached data.</li>
|
||||
<li>For some queries, the user will be able to perform the query without using HTTPS (unless Apache is configured to require it) because the Blackbook call can be skipped.</li>
|
||||
<li>Information in the cache is stored without encryption. Any local user can read the data, and any remote user with access to the Memcache port can do the same.</li>
|
||||
<li>If the query cache and the Memcached RDF source are being used at the same time, in some circumstances a carefully constructed query could allow data in the query cache to be read through the Memcached RDF source. This is because both data sets are stored on the same server in the same namespace.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-TheMemcachedRDFsource"></a>The Memcached RDF source</h3>
|
||||
|
||||
<p>The Memcached RDF source is similar to the Test RDF source, except instead of using hardcoded data, it reads the test data from a Memcached in-memory database. Note that this does not provide any functionality for caching query results from other RDF sources. In other words, Memcached is not being used for its traditional purpose -- this functionality is only to assist the prototyping of applications when the actual RDF store cannot be accessed.</p>
|
||||
|
||||
<p>To use this functionality, set the aqMemcacheHost and aqMemcachePort global variables in LocalSettings.php to the appropriate values. Create an RDF source with a datastore type of "Memcached", and the appropriate wiki namespace ID, wiki namespace, and datastore URI prefix. The data in the Memcached datatore must be encoded in N-Triples format and keyed by URI (with one entity per cache entry).</p>
|
||||
|
||||
<p>Be warned that enabling the Memcached data source will also enable the Blackbook Cache described above, because the same parameters will be used to enable both.</p>
|
||||
</body></html>
|
||||
14
aqueductapi.html
Normal file
14
aqueductapi.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<html><body>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-TheAqueductAPI"></a>The Aqueduct API</h3>
|
||||
|
||||
<p>When the Aqueduct extension is installed, a Mediawiki API is installed along with it. This Mediawiki API allows external data consumers to query any semantic data that is accessible through the wiki.</p>
|
||||
|
||||
<p>Instead of directly working with RDF sources, the API acts as a "lens" that maps multiple RDF sources into a single wiki. Therefore, all queries are performed using wiki page titles (instead of directly providing URIs and datasource names.)</p>
|
||||
|
||||
<p>The API is invoked from the api.php file that is built into Mediawiki with the "aqueduct" API action. The API has one parameter ("subject") which should equal the title of the page that is being queried. The API will retrieve all semantic data associated with that page and return it as a JSON object. The JSON object will be an object with one property. The name of the property will be the title of the page that was queried, and the value will be an RDF-JSON object representing the RDF that was returned. Read the <a href="http://n2.talis.com/wiki/RDF_JSON_Specification">RDF-JSON specification</a> for more details. </p>
|
||||
|
||||
<p>There is also a "set" operation that allows you to modify individual triples in Blackbook. The "subject" parameter receives the subject of the triple that will be modified. If "subjecttype" is omitted or set to "page", "subject" should be a wiki page title (as above), while if "subjecttype" is set to "uri", the subject should be an RDF URI. Note that even if "subjecttype" is set to "uri", the URI must still correspond to a page in the wiki, so Aqueduct will know which server should store the URI. "predicateURI" is the predicate of the triple. "object" is a URI or a literal. "objecttype" should be the string "literal" or "uri" to represent the type of the object. The set operation will work on the datasource corresponding to the "Datastore Name" of the RDF source. The entire RDF entity will be materialized, all statements with a predicate matching the given predicate will be removed, the triples will be added, and the entity will be committed to Blackbook. Be warned that, depending on your datasource, triples with special reification (such as "role") could lose their reification during the set operation. If you are using these reified properties in your application, thoroughly test all reification scenarios with the set API.</p>
|
||||
|
||||
<p>For the set to work, the datasource must be an assertions datasouce, created as described in the Siphon section below. (The same Blackbook API call is used to persist data here and in Siphon.) </p>
|
||||
</body></html>
|
||||
38
aqueductinstallation.html
Normal file
38
aqueductinstallation.html
Normal file
@@ -0,0 +1,38 @@
|
||||
<html><body>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-InstallingtheAqueductextension%26nbsp%3B"></a>Installing the Aqueduct extension </h3>
|
||||
|
||||
<p>Installing Aqueduct requires Mediawiki 1.14.0 or higher. Semantic Mediawiki is not required.</p>
|
||||
|
||||
<p>1. Install Mediawiki and verify that it works</p>
|
||||
|
||||
<p>2. Due to a Mediawiki bug (at least in 1.15.1), you need to modify a line in the Mediawiki source code. Load /path/to/wiki/includes/api/ApiFormatJson_json.php . On or around line 818, locate the following line:</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java"><span class="code-keyword">if</span> (class_exists('pear')) {</pre>
|
||||
</div></div>
|
||||
<p>Change it to:</p>
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java"><span class="code-keyword">if</span> (FALSE) {</pre>
|
||||
</div></div>
|
||||
|
||||
<p>Failure to do this will cause extremely slow Mediawiki performance or timeouts when using the widgets or making API calls. </p>
|
||||
|
||||
<p>3. Place the AqueductExtension folder in the extensions folder of your Mediawiki installation -- for example, /var/www/wiki/extensions/AqueductExtension. Note that the default location relative to Mediawiki must be used -- a directory called "extensions" must be in your mediawiki directory, and the AqueductExtension directory must be inside "extensions".</p>
|
||||
|
||||
<p>4. Enable the extension by placing the following line at the bottom of your LocalSettings.php file: require_once( 'extensions/AqueductExtension/AqueductExtension.php' );</p>
|
||||
|
||||
<p>5. There is a file called AqueductSQLTbl.sql in the AqueductExtension directory. Run this file against your wiki's MySQL database to generate the database tables.<br/>
|
||||
</p>
|
||||
|
||||
<p>Aqueduct is now ready to configure. At this point, your wiki should be functional with no errors or unexpected behavior.</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Troubleshooting"></a>Troubleshooting</h3>
|
||||
|
||||
<p>Misconfigurations can result in Aqueduct crashing and "Segmentation fault" appearing in your apache log file. Widgets failing with "Error 200" are another symptom of this problem. ("Error 200" often means that Apache crashed while performing the query, and the Segmentation Fault can be seen in the Apache log file.)</p>
|
||||
|
||||
<p>If you are seeing segmentation faults, try the following troubleshooting steps: </p>
|
||||
<ol>
|
||||
<li>Ensure that you are using the latest version of PHP. If you are using Aqueduct with Blackbook, ensure that you are using the latest version of Java. If you compile PHP yourself or supply your own OpenSSL library, ensure that the latest version of OpenSSL is being used as well. Aqueduct has been tested with Java 1.6.0_16, PHP 5.2.6, and OpenSSL 0.9.8g.</li>
|
||||
<li>Ensure that apache is using the "prefork" MPM and not one of the threaded MPMs. PHP is not thread-safe and should not be used with a threaded MPM.</li>
|
||||
</ol>
|
||||
</body></html>
|
||||
444
arc/ARC2.php
Normal file
444
arc/ARC2.php
Normal file
@@ -0,0 +1,444 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 core class (static, not instantiated)
|
||||
*
|
||||
* @author Benjamin Nowack
|
||||
* @license <http://arc.semsol.org/license>
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2010-01-04
|
||||
*/
|
||||
|
||||
class ARC2 {
|
||||
|
||||
function getVersion() {
|
||||
return '2010-01-04';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function setStatic($val) {
|
||||
static $arc_static = '';
|
||||
if ($val) $arc_static = $val; /* set */
|
||||
if (!$val) return $arc_static; /* get */
|
||||
}
|
||||
|
||||
function getStatic() {
|
||||
return ARC2::setStatic('');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getIncPath($f = '') {
|
||||
$r = realpath(dirname(__FILE__)) . '/';
|
||||
$dirs = array(
|
||||
'plugin' => 'plugins',
|
||||
'trigger' => 'triggers',
|
||||
'store' => 'store',
|
||||
'serializer' => 'serializers',
|
||||
'extractor' => 'extractors',
|
||||
'sparqlscript' => 'sparqlscript',
|
||||
'parser' => 'parsers',
|
||||
);
|
||||
foreach ($dirs as $k => $dir) {
|
||||
if (preg_match('/' . $k . '/i', $f)) {
|
||||
$r .= $dir . '/';
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getScriptURI() {
|
||||
if (isset($_SERVER) && isset($_SERVER['SERVER_NAME'])) {
|
||||
return preg_replace('/^([a-z]+)\/.*$/', '\\1', strtolower($_SERVER['SERVER_PROTOCOL'])) .
|
||||
'://' . $_SERVER['SERVER_NAME'] .
|
||||
($_SERVER['SERVER_PORT'] != 80 ? ':' . $_SERVER['SERVER_PORT'] : '') .
|
||||
$_SERVER['SCRIPT_NAME'];
|
||||
}
|
||||
elseif (isset($_SERVER['SCRIPT_FILENAME'])) {
|
||||
return 'file://' . realpath($_SERVER['SCRIPT_FILENAME']);
|
||||
}
|
||||
return 'http://localhost/unknown_path';
|
||||
}
|
||||
|
||||
function getRequestURI() {
|
||||
if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) {
|
||||
return preg_replace('/^([a-z]+)\/.*$/', '\\1', strtolower($_SERVER['SERVER_PROTOCOL'])) .
|
||||
'://' . $_SERVER['SERVER_NAME'] .
|
||||
($_SERVER['SERVER_PORT'] != 80 ? ':' . $_SERVER['SERVER_PORT'] : '') .
|
||||
$_SERVER['REQUEST_URI'];
|
||||
}
|
||||
return ARC2::getScriptURI();
|
||||
}
|
||||
|
||||
function inc($f, $path = '') {
|
||||
$prefix = 'ARC2';
|
||||
if (preg_match('/^([^\_]+)\_(.*)$/', $f, $m)) {
|
||||
$prefix = $m[1];
|
||||
$f = $m[2];
|
||||
}
|
||||
$inc_path = $path ? $path : ARC2::getIncPath($f);
|
||||
$path = $inc_path . $prefix . '_' . urlencode($f) . '.php';
|
||||
if (file_exists($path)) {
|
||||
include_once($path);
|
||||
return 1;
|
||||
}
|
||||
if ($prefix != 'ARC2') {
|
||||
$path = $inc_path . strtolower($prefix) . '/' . $prefix . '_' . urlencode($f) . '.php';
|
||||
if (file_exists($path)) {
|
||||
include_once($path);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function mtime(){
|
||||
list($msec, $sec) = explode(" ", microtime());
|
||||
return ((float)$msec + (float)$sec);
|
||||
}
|
||||
|
||||
function x($re, $v, $options = 'si') {
|
||||
return preg_match("/^\s*" . $re . "(.*)$/" . $options, $v, $m) ? $m : false;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getFormat($val, $mtype = '', $ext = '') {
|
||||
ARC2::inc('getFormat');
|
||||
return ARC2_getFormat($val, $mtype, $ext);
|
||||
}
|
||||
|
||||
function getPreferredFormat($default = 'plain') {
|
||||
ARC2::inc('getPreferredFormat');
|
||||
return ARC2_getPreferredFormat($default);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function toUTF8($v) {
|
||||
if (utf8_decode($v) == $v) return $v;
|
||||
$v = (strpos(utf8_decode(str_replace('?', '', $v)), '?') === false) ? utf8_decode($v) : $v;
|
||||
return preg_replace_callback('/([\x00-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3}|[\xf8-\xfb][\x80-\xbf]{4}|[\xfc-\xfd][\x80-\xbf]{5}|[^\x00-\x7f])/', array('ARC2', 'getUTF8Char'), $v);
|
||||
}
|
||||
|
||||
function getUTF8Char($v) {
|
||||
$val = $v[1];
|
||||
return (strlen(trim($val)) === 1) ? utf8_encode($val) : $val;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function splitURI($v) {
|
||||
/* the following namespaces may lead to conflated URIs,
|
||||
* we have to set the split position manually
|
||||
*/
|
||||
if (strpos($v, 'www.w3.org')) {
|
||||
$specials = array(
|
||||
'http://www.w3.org/XML/1998/namespace',
|
||||
'http://www.w3.org/2005/Atom',
|
||||
'http://www.w3.org/1999/xhtml',
|
||||
);
|
||||
foreach ($specials as $ns) {
|
||||
if (strpos($v, $ns) === 0) {
|
||||
$local_part = substr($v, strlen($ns));
|
||||
if (!preg_match('/^[\/\#]/', $local_part)) {
|
||||
return array($ns, $local_part);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* auto-splitting on / or # */
|
||||
//$re = '^(.*?)([A-Z_a-z][-A-Z_a-z0-9.]*)$';
|
||||
if (preg_match('/^(.*[\/\#])([^\/\#]+)$/', $v, $m)) return array($m[1], $m[2]);
|
||||
/* auto-splitting on last special char, e.g. urn:foo:bar */
|
||||
if (preg_match('/^(.*[\:\/])([^\:\/]+)$/', $v, $m)) return array($m[1], $m[2]);
|
||||
return array($v, '');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getSimpleIndex($triples, $flatten_objects = 1, $vals = '') {
|
||||
$r = array();
|
||||
foreach ($triples as $t) {
|
||||
$skip_t = 0;
|
||||
foreach (array('s', 'p', 'o') as $term) {
|
||||
$$term = $t[$term];
|
||||
/* template var */
|
||||
if (isset($t[$term . '_type']) && ($t[$term . '_type'] == 'var')) {
|
||||
$val = isset($vals[$$term]) ? $vals[$$term] : '';
|
||||
$skip_t = isset($vals[$$term]) ? $skip_t : 1;
|
||||
$type = '';
|
||||
$type = !$type && isset($vals[$$term . ' type']) ? $vals[$$term . ' type'] : $type;
|
||||
$type = !$type && preg_match('/^\_\:/', $val) ? 'bnode' : $type;
|
||||
if ($term == 'o') {
|
||||
$type = !$type && (preg_match('/\s/s', $val) || !preg_match('/\:/', $val)) ? 'literal' : $type;
|
||||
$type = !$type && !preg_match('/[\/]/', $val) ? 'literal' : $type;
|
||||
}
|
||||
$type = !$type ? 'uri' : $type;
|
||||
$t[$term . '_type'] = $type;
|
||||
$$term = $val;
|
||||
}
|
||||
}
|
||||
if ($skip_t) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($r[$s])) $r[$s] = array();
|
||||
if (!isset($r[$s][$p])) $r[$s][$p] = array();
|
||||
if ($flatten_objects) {
|
||||
if (!in_array($o, $r[$s][$p])) $r[$s][$p][] = $o;
|
||||
}
|
||||
else {
|
||||
$o = array('value' => $o);
|
||||
foreach (array('lang', 'type', 'datatype') as $suffix) {
|
||||
if (isset($t['o_' . $suffix]) && $t['o_' . $suffix]) {
|
||||
$o[$suffix] = $t['o_' . $suffix];
|
||||
}
|
||||
elseif (isset($t['o ' . $suffix]) && $t['o ' . $suffix]) {
|
||||
$o[$suffix] = $t['o ' . $suffix];
|
||||
}
|
||||
}
|
||||
if (!in_array($o, $r[$s][$p])) {
|
||||
$r[$s][$p][] = $o;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getTriplesFromIndex($index) {
|
||||
$r = array();
|
||||
foreach ($index as $s => $ps) {
|
||||
foreach ($ps as $p => $os) {
|
||||
foreach ($os as $o) {
|
||||
$r[] = array(
|
||||
's' => $s,
|
||||
'p' => $p,
|
||||
'o' => $o['value'],
|
||||
's_type' => preg_match('/^\_\:/', $s) ? 'bnode' : 'uri',
|
||||
'o_type' => $o['type'],
|
||||
'o_datatype' => isset($o['datatype']) ? $o['datatype'] : '',
|
||||
'o_lang' => isset($o['lang']) ? $o['lang'] : '',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getMergedIndex() {
|
||||
$r = array();
|
||||
foreach (func_get_args() as $index) {
|
||||
foreach ($index as $s => $ps) {
|
||||
if (!isset($r[$s])) $r[$s] = array();
|
||||
foreach ($ps as $p => $os) {
|
||||
if (!isset($r[$s][$p])) $r[$s][$p] = array();
|
||||
foreach ($os as $o) {
|
||||
if (!in_array($o, $r[$s][$p])) {
|
||||
$r[$s][$p][] = $o;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getCleanedIndex() {/* removes triples from a given index */
|
||||
$indexes = func_get_args();
|
||||
$r = $indexes[0];
|
||||
for ($i = 1, $i_max = count($indexes); $i < $i_max; $i++) {
|
||||
$index = $indexes[$i];
|
||||
foreach ($index as $s => $ps) {
|
||||
if (!isset($r[$s])) continue;
|
||||
foreach ($ps as $p => $os) {
|
||||
if (!isset($r[$s][$p])) continue;
|
||||
$r_os = $r[$s][$p];
|
||||
$new_os = array();
|
||||
foreach ($r_os as $r_o) {
|
||||
$r_o_val = is_array($r_o) ? $r_o['value'] : $r_o;
|
||||
$keep = 1;
|
||||
foreach ($os as $o) {
|
||||
$del_o_val = is_array($o) ? $o['value'] : $o;
|
||||
if ($del_o_val == $r_o_val) {
|
||||
$keep = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($keep) {
|
||||
$new_os[] = $r_o;
|
||||
}
|
||||
}
|
||||
if ($new_os) {
|
||||
$r[$s][$p] = $new_os;
|
||||
}
|
||||
else {
|
||||
unset($r[$s][$p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* check r */
|
||||
$has_data = 0;
|
||||
foreach ($r as $s => $ps) {
|
||||
if ($ps) {
|
||||
$has_data = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $has_data ? $r : array();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getStructType($v) {
|
||||
/* string */
|
||||
if (is_string($v)) return 'string';
|
||||
/* triples */
|
||||
if (isset($v[0]) && isset($v[0]['s']) && isset($v[0]['p'])) return 'triples';
|
||||
/* index */
|
||||
foreach ($v as $s => $ps) {
|
||||
if (is_array($ps)) {
|
||||
foreach ($ps as $p => $os) {
|
||||
if (is_array($os) && isset($os[0]) && isset($os[0]['value'])) return 'index';
|
||||
}
|
||||
}
|
||||
}
|
||||
/* array */
|
||||
return 'array';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getComponent($name, $a = '', $caller = '') {
|
||||
ARC2::inc($name);
|
||||
$prefix = 'ARC2';
|
||||
if (preg_match('/^([^\_]+)\_(.+)$/', $name, $m)) {
|
||||
$prefix = $m[1];
|
||||
$name = $m[2];
|
||||
}
|
||||
$cls = $prefix . '_' . $name;
|
||||
if (!$caller) $caller = new stdClass();
|
||||
return new $cls($a, $caller);
|
||||
}
|
||||
|
||||
/* resource */
|
||||
|
||||
function getResource($a = '') {
|
||||
return ARC2::getComponent('Resource', $a);
|
||||
}
|
||||
|
||||
/* parsers */
|
||||
|
||||
function getParser($prefix, $a = '') {
|
||||
return ARC2::getComponent($prefix . 'Parser', $a);
|
||||
}
|
||||
|
||||
function getRDFParser($a = '') {
|
||||
return ARC2::getParser('RDF', $a);
|
||||
}
|
||||
|
||||
function getRDFXMLParser($a = '') {
|
||||
return ARC2::getParser('RDFXML', $a);
|
||||
}
|
||||
|
||||
function getTurtleParser($a = '') {
|
||||
return ARC2::getParser('Turtle', $a);
|
||||
}
|
||||
|
||||
function getRSSParser($a = '') {
|
||||
return ARC2::getParser('RSS', $a);
|
||||
}
|
||||
|
||||
function getSemHTMLParser($a = '') {
|
||||
return ARC2::getParser('SemHTML', $a);
|
||||
}
|
||||
|
||||
function getSPARQLParser($a = '') {
|
||||
return ARC2::getComponent('SPARQLParser', $a);
|
||||
}
|
||||
|
||||
function getSPARQLPlusParser($a = '') {
|
||||
return ARC2::getParser('SPARQLPlus', $a);
|
||||
}
|
||||
|
||||
function getSPARQLXMLResultParser($a = '') {
|
||||
return ARC2::getParser('SPARQLXMLResult', $a);
|
||||
}
|
||||
|
||||
function getJSONParser($a = '') {
|
||||
return ARC2::getParser('JSON', $a);
|
||||
}
|
||||
|
||||
function getSGAJSONParser($a = '') {
|
||||
return ARC2::getParser('SGAJSON', $a);
|
||||
}
|
||||
|
||||
function getCBJSONParser($a = '') {
|
||||
return ARC2::getParser('CBJSON', $a);
|
||||
}
|
||||
|
||||
function getSPARQLScriptParser($a = '') {
|
||||
return ARC2::getParser('SPARQLScript', $a);
|
||||
}
|
||||
|
||||
/* store */
|
||||
|
||||
function getStore($a = '', $caller = '') {
|
||||
return ARC2::getComponent('Store', $a, $caller);
|
||||
}
|
||||
|
||||
function getStoreEndpoint($a = '') {
|
||||
return ARC2::getComponent('StoreEndpoint', $a);
|
||||
}
|
||||
|
||||
function getRemoteStore($a = '') {
|
||||
return ARC2::getComponent('RemoteStore', $a);
|
||||
}
|
||||
|
||||
function getMemStore($a = '') {
|
||||
return ARC2::getComponent('MemStore', $a);
|
||||
}
|
||||
|
||||
/* serializers */
|
||||
|
||||
function getSer($prefix, $a = '') {
|
||||
return ARC2::getComponent($prefix . 'Serializer', $a);
|
||||
}
|
||||
|
||||
function getTurtleSerializer($a = '') {
|
||||
return ARC2::getSer('Turtle', $a);
|
||||
}
|
||||
|
||||
function getRDFXMLSerializer($a = '') {
|
||||
return ARC2::getSer('RDFXML', $a);
|
||||
}
|
||||
|
||||
function getNTriplesSerializer($a = '') {
|
||||
return ARC2::getSer('NTriples', $a);
|
||||
}
|
||||
|
||||
function getRDFJSONSerializer($a = '') {
|
||||
return ARC2::getSer('RDFJSON', $a);
|
||||
}
|
||||
|
||||
function getPOSHRDFSerializer($a = '') {
|
||||
return ARC2::getSer('POSHRDF', $a);
|
||||
}
|
||||
|
||||
function getRSS10Serializer($a = '') {
|
||||
return ARC2::getSer('RSS10', $a);
|
||||
}
|
||||
|
||||
/* sparqlscript */
|
||||
|
||||
function getSPARQLScriptProcessor($a = '') {
|
||||
return ARC2::getComponent('SPARQLScriptProcessor', $a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
413
arc/ARC2_Class.php
Normal file
413
arc/ARC2_Class.php
Normal file
@@ -0,0 +1,413 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 base class
|
||||
*
|
||||
* @author Benjamin Nowack
|
||||
* @license <http://arc.semsol.org/license>
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-12-08
|
||||
*/
|
||||
|
||||
class ARC2_Class {
|
||||
|
||||
/* */
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
$a = is_array($a) ? $a : array();
|
||||
$this->a = $a;
|
||||
$this->caller = &$caller;
|
||||
$this->__init();
|
||||
}
|
||||
|
||||
function ARC2_Class($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __destruct() {
|
||||
//echo "\ndestructing " . get_class($this);
|
||||
}
|
||||
|
||||
function __init() {/* base, time_limit */
|
||||
if (!$_POST && isset($GLOBALS['HTTP_RAW_POST_DATA'])) parse_str($GLOBALS['HTTP_RAW_POST_DATA'], $_POST); /* php5 bug */
|
||||
$this->inc_path = ARC2::getIncPath();
|
||||
$this->ns_count = 0;
|
||||
$this->nsp = array('http://www.w3.org/1999/02/22-rdf-syntax-ns#' => 'rdf');
|
||||
$this->used_ns = array('http://www.w3.org/1999/02/22-rdf-syntax-ns#');
|
||||
$this->ns = $this->v('ns', array(), $this->a);
|
||||
|
||||
$this->base = $this->v('base', ARC2::getRequestURI(), $this->a);
|
||||
$this->errors = array();
|
||||
$this->warnings = array();
|
||||
$this->adjust_utf8 = $this->v('adjust_utf8', 0, $this->a);
|
||||
$this->max_errors = $this->v('max_errors', 25, $this->a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function v($name, $default = false, $o = false) {/* value if set */
|
||||
if ($o === false) $o =& $this;
|
||||
if (is_array($o)) {
|
||||
return isset($o[$name]) ? $o[$name] : $default;
|
||||
}
|
||||
return isset($o->$name) ? $o->$name : $default;
|
||||
}
|
||||
|
||||
function v1($name, $default = false, $o = false) {/* value if 1 (= not empty) */
|
||||
if ($o === false) $o =& $this;
|
||||
if (is_array($o)) {
|
||||
return (isset($o[$name]) && $o[$name]) ? $o[$name] : $default;
|
||||
}
|
||||
return (isset($o->$name) && $o->$name) ? $o->$name : $default;
|
||||
}
|
||||
|
||||
function m($name, $a = false, $default = false, $o = false) {/* call method */
|
||||
if ($o === false) $o =& $this;
|
||||
return method_exists($o, $name) ? $o->$name($a) : $default;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function camelCase($v, $lc_first = 0) {
|
||||
$r = ucfirst($v);
|
||||
while (preg_match('/^(.*)[\-\_ ](.*)$/', $r, $m)) {
|
||||
$r = $m[1] . ucfirst($m[2]);
|
||||
}
|
||||
return $lc_first ? strtolower(substr($r, 0, 1)) . substr($r, 1) : $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function addError($v) {
|
||||
if (!in_array($v, $this->errors)) {
|
||||
$this->errors[] = $v;
|
||||
}
|
||||
if ($this->caller && method_exists($this->caller, 'addError')) {
|
||||
$glue = strpos($v, ' in ') ? ' via ' : ' in ';
|
||||
$this->caller->addError($v . $glue . get_class($this));
|
||||
}
|
||||
if (count($this->errors) > $this->max_errors) {
|
||||
die('Too many errors (limit: ' . $this->max_errors . '): ' . print_r($this->errors, 1));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getErrors() {
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
function getWarnings() {
|
||||
return $this->warnings;
|
||||
}
|
||||
|
||||
function resetErrors() {
|
||||
$this->errors = array();
|
||||
if ($this->caller && method_exists($this->caller, 'resetErrors')) {
|
||||
$this->caller->resetErrors();
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function splitURI($v) {
|
||||
return ARC2::splitURI($v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getPName($v, $connector = ':') {
|
||||
/* is already a pname */
|
||||
if ($ns = $this->getPNameNamespace($v)) {
|
||||
if (!in_array($ns, $this->used_ns)) $this->used_ns[] = $ns;
|
||||
return $v;
|
||||
}
|
||||
/* new pname */
|
||||
if ($parts = $this->splitURI($v)) {
|
||||
/* known prefix */
|
||||
foreach ($this->ns as $prefix => $ns) {
|
||||
if ($parts[0] == $ns) {
|
||||
if (!in_array($ns, $this->used_ns)) $this->used_ns[] = $ns;
|
||||
return $prefix . $connector . $parts[1];
|
||||
}
|
||||
}
|
||||
/* new prefix */
|
||||
$prefix = $this->getPrefix($parts[0]);
|
||||
return $prefix . $connector . $parts[1];
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
|
||||
function getPNameNamespace($v) {
|
||||
if (!preg_match('/^([a-z0-9\_\-]+)\:([a-z0-9\_\-\.\%]*)$/i', $v, $m)) return 0;
|
||||
if (!isset($this->ns[$m[1]])) return 0;
|
||||
return $this->ns[$m[1]];
|
||||
}
|
||||
|
||||
function getPrefix($ns) {
|
||||
if (!isset($this->nsp[$ns])) {
|
||||
$this->ns['ns' . $this->ns_count] = $ns;
|
||||
$this->nsp[$ns] = 'ns' . $this->ns_count;
|
||||
$this->ns_count++;
|
||||
}
|
||||
if (!in_array($ns, $this->used_ns)) $this->used_ns[] = $ns;
|
||||
return $this->nsp[$ns];
|
||||
}
|
||||
|
||||
function expandPName($v, $connector = ':') {
|
||||
$re = '/^([a-z0-9\_\-]+)\:([a-z0-9\_\-]+)$/i';
|
||||
if ($connector == '-') {
|
||||
$re = '/^([a-z0-9\_]+)\-([a-z0-9\_\-]+)$/i';
|
||||
}
|
||||
if (preg_match($re, $v, $m) && isset($this->ns[$m[1]])) {
|
||||
return $this->ns[$m[1]] . $m[2];
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
|
||||
function expandPNames($index) {
|
||||
$r = array();
|
||||
foreach ($index as $s => $ps) {
|
||||
$s = $this->expandPName($s);
|
||||
$r[$s] = array();
|
||||
foreach ($ps as $p => $os) {
|
||||
$p = $this->expandPName($p);
|
||||
if (!is_array($os)) $os = array($os);
|
||||
foreach ($os as $i => $o) {
|
||||
if (!is_array($o)) {
|
||||
$o_val = $this->expandPName($o);
|
||||
$o_type = preg_match('/^[a-z]+\:[^\s]+$/si', $o_val) ? 'uri' : 'literal';
|
||||
$o = array('value' => $o_val, 'type' => $o_type);
|
||||
}
|
||||
$os[$i] = $o;
|
||||
}
|
||||
$r[$s][$p] = $os;
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function calcURI($path, $base = "") {
|
||||
/* quick check */
|
||||
if (preg_match("/^[a-z0-9\_]+\:/i", $path)) {/* abs path or bnode */
|
||||
return $path;
|
||||
}
|
||||
if (preg_match('/^\$\{.*\}/', $path)) {/* placeholder, assume abs URI */
|
||||
return $path;
|
||||
}
|
||||
if (preg_match("/^\/\//", $path)) {/* net path, assume http */
|
||||
return 'http:' . $path;
|
||||
}
|
||||
/* other URIs */
|
||||
$base = $base ? $base : $this->base;
|
||||
$base = preg_replace('/\#.*$/', '', $base);
|
||||
if ($path === true) {/* empty (but valid) URIref via turtle parser: <> */
|
||||
return $base;
|
||||
}
|
||||
$path = preg_replace("/^\.\//", '', $path);
|
||||
$root = preg_match('/(^[a-z0-9]+\:[\/]{1,3}[^\/]+)[\/|$]/i', $base, $m) ? $m[1] : $base; /* w/o trailing slash */
|
||||
$base .= ($base == $root) ? '/' : '';
|
||||
if (preg_match('/^\//', $path)) {/* leading slash */
|
||||
return $root . $path;
|
||||
}
|
||||
if (!$path) {
|
||||
return $base;
|
||||
}
|
||||
if (preg_match('/^([\#\?])/', $path, $m)) {
|
||||
return preg_replace('/\\' .$m[1]. '.*$/', '', $base) . $path;
|
||||
}
|
||||
if (preg_match('/^(\&)(.*)$/', $path, $m)) {/* not perfect yet */
|
||||
return preg_match('/\?/', $base) ? $base . $m[1] . $m[2] : $base . '?' . $m[2];
|
||||
}
|
||||
if (preg_match("/^[a-z0-9]+\:/i", $path)) {/* abs path */
|
||||
return $path;
|
||||
}
|
||||
/* rel path: remove stuff after last slash */
|
||||
$base = substr($base, 0, strrpos($base, '/')+1);
|
||||
/* resolve ../ */
|
||||
while (preg_match('/^(\.\.\/)(.*)$/', $path, $m)) {
|
||||
$path = $m[2];
|
||||
$base = ($base == $root.'/') ? $base : preg_replace('/^(.*\/)[^\/]+\/$/', '\\1', $base);
|
||||
}
|
||||
return $base . $path;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function calcBase($path) {
|
||||
$r = $path;
|
||||
$r = preg_replace('/\#.*$/', '', $r);/* remove hash */
|
||||
$r = preg_replace('/^\/\//', 'http://', $r);/* net path (//), assume http */
|
||||
if (preg_match('/^[a-z0-9]+\:/', $r)) {/* scheme, abs path */
|
||||
while (preg_match('/^(.+\/)(\.\.\/.*)$/U', $r, $m)) {
|
||||
$r = $this->calcURI($m[1], $m[2]);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
return 'file://' . realpath($r);/* real path */
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getResource($uri, $store_or_props = '') {
|
||||
$res = ARC2::getResource($this->a);
|
||||
$res->setURI($uri);
|
||||
if (is_array($store_or_props)) {
|
||||
$res->setProps($store_or_props);
|
||||
}
|
||||
else {
|
||||
$res->setStore($store_or_props);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
function toIndex($v) {
|
||||
if (is_array($v)) {
|
||||
if (isset($v[0]) && isset($v[0]['s'])) return ARC2::getSimpleIndex($v, 0);
|
||||
return $v;
|
||||
}
|
||||
$parser = ARC2::getRDFParser($this->a);
|
||||
if ($v && !preg_match('/\s/', $v)) {/* assume graph URI */
|
||||
$parser->parse($v);
|
||||
}
|
||||
else {
|
||||
$parser->parse('', $v);
|
||||
}
|
||||
return $parser->getSimpleIndex(0);
|
||||
}
|
||||
|
||||
function toTriples($v) {
|
||||
if (is_array($v)) {
|
||||
if (isset($v[0]) && isset($v[0]['s'])) return $v;
|
||||
return ARC2::getTriplesFromIndex($v);
|
||||
}
|
||||
$parser = ARC2::getRDFParser($this->a);
|
||||
if ($v && !preg_match('/\s/', $v)) {/* assume graph URI */
|
||||
$parser->parse($v);
|
||||
}
|
||||
else {
|
||||
$parser->parse('', $v);
|
||||
}
|
||||
return $parser->getTriples();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function toNTriples($v, $ns = '', $raw = 0) {
|
||||
ARC2::inc('NTriplesSerializer');
|
||||
if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
|
||||
$ser = new ARC2_NTriplesSerializer(array_merge($this->a, array('ns' => $ns)), $this);
|
||||
return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v, $raw) : $ser->getSerializedIndex($v, $raw);
|
||||
}
|
||||
|
||||
function toTurtle($v, $ns = '', $raw = 0) {
|
||||
ARC2::inc('TurtleSerializer');
|
||||
if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
|
||||
$ser = new ARC2_TurtleSerializer(array_merge($this->a, array('ns' => $ns)), $this);
|
||||
return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v, $raw) : $ser->getSerializedIndex($v, $raw);
|
||||
}
|
||||
|
||||
function toRDFXML($v, $ns = '', $raw = 0) {
|
||||
ARC2::inc('RDFXMLSerializer');
|
||||
if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
|
||||
$ser = new ARC2_RDFXMLSerializer(array_merge($this->a, array('ns' => $ns)), $this);
|
||||
return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v, $raw) : $ser->getSerializedIndex($v, $raw);
|
||||
}
|
||||
|
||||
function toRDFJSON($v, $ns = '') {
|
||||
ARC2::inc('RDFJSONSerializer');
|
||||
if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
|
||||
$ser = new ARC2_RDFJSONSerializer(array_merge($this->a, array('ns' => $ns)), $this);
|
||||
return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v) : $ser->getSerializedIndex($v);
|
||||
}
|
||||
|
||||
function toRSS10($v, $ns = '') {
|
||||
ARC2::inc('RSS10Serializer');
|
||||
if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
|
||||
$ser = new ARC2_RSS10Serializer(array_merge($this->a, array('ns' => $ns)), $this);
|
||||
return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v) : $ser->getSerializedIndex($v);
|
||||
}
|
||||
|
||||
function toLegacyXML($v, $ns = '') {
|
||||
ARC2::inc('LegacyXMLSerializer');
|
||||
if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
|
||||
$ser = new ARC2_LegacyXMLSerializer(array_merge($this->a, array('ns' => $ns)), $this);
|
||||
return $ser->getSerializedArray($v);
|
||||
}
|
||||
|
||||
function toLegacyJSON($v, $ns = '') {
|
||||
ARC2::inc('LegacyJSONSerializer');
|
||||
if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
|
||||
$ser = new ARC2_LegacyJSONSerializer(array_merge($this->a, array('ns' => $ns)), $this);
|
||||
return $ser->getSerializedArray($v);
|
||||
}
|
||||
|
||||
function toLegacyHTML($v, $ns = '') {
|
||||
ARC2::inc('LegacyHTMLSerializer');
|
||||
if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
|
||||
$ser = new ARC2_LegacyHTMLSerializer(array_merge($this->a, array('ns' => $ns)), $this);
|
||||
return $ser->getSerializedArray($v);
|
||||
}
|
||||
|
||||
function toHTML($v, $ns = '') {
|
||||
ARC2::inc('POSHRDFSerializer');
|
||||
if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
|
||||
$ser = new ARC2_POSHRDFSerializer(array_merge($this->a, array('ns' => $ns)), $this);
|
||||
return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v) : $ser->getSerializedIndex($v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getFilledTemplate($t, $vals, $g = '') {
|
||||
$parser = ARC2::getTurtleParser();
|
||||
$parser->parse($g, $this->getTurtleHead() . $t);
|
||||
return $parser->getSimpleIndex(0, $vals);
|
||||
}
|
||||
|
||||
function getTurtleHead() {
|
||||
$r = '';
|
||||
$ns = $this->v('ns', array(), $this->a);
|
||||
foreach ($ns as $k => $v) {
|
||||
$r .= "@prefix " . $k . ": <" .$v. "> .\n";
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function completeQuery($q, $ns = '') {
|
||||
if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
|
||||
$added_prefixes = array();
|
||||
$prologue = '';
|
||||
foreach ($ns as $k => $v) {
|
||||
$k = rtrim($k, ':');
|
||||
if (in_array($k, $added_prefixes)) continue;
|
||||
if (preg_match('/(^|\s)' . $k . ':/s', $q) && !preg_match('/PREFIX\s+' . $k . '\:/is', $q)) {
|
||||
$prologue .= "\n" . 'PREFIX ' . $k . ': <' . $v . '>';
|
||||
}
|
||||
$added_prefixes[] = $k;
|
||||
}
|
||||
return $prologue . "\n" . $q;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function toUTF8($str) {
|
||||
return $this->adjust_utf8 ? ARC2::toUTF8($str) : $str;
|
||||
}
|
||||
|
||||
function toDataURI($str) {
|
||||
return 'data:text/plain;charset=utf-8,' . rawurlencode($str);
|
||||
}
|
||||
|
||||
function fromDataURI($str) {
|
||||
return str_replace('data:text/plain;charset=utf-8,', '', rawurldecode($str));
|
||||
}
|
||||
|
||||
/* prevent SQL injections via SPARQL REGEX */
|
||||
|
||||
function checkRegex($str) {
|
||||
return addslashes($str); // @@todo extend
|
||||
}
|
||||
|
||||
/* */
|
||||
}
|
||||
391
arc/ARC2_Reader.php
Normal file
391
arc/ARC2_Reader.php
Normal file
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 Web Client
|
||||
*
|
||||
* @author Benjamin Nowack
|
||||
* @license <http://arc.semsol.org/license>
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-12-08
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_Reader extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_Reader($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* inc_path, proxy_host, proxy_port, proxy_skip, http_accept_header, http_user_agent_header, max_redirects */
|
||||
parent::__init();
|
||||
$this->http_method = $this->v('http_method', 'GET', $this->a);
|
||||
$this->message_body = $this->v('message_body', '', $this->a);;
|
||||
$this->http_accept_header = $this->v('http_accept_header', 'Accept: application/rdf+xml; q=0.9, */*; q=0.1', $this->a);
|
||||
$this->http_user_agent_header = $this->v('http_user_agent_header', 'User-Agent: ARC Reader (http://arc.semsol.org/)', $this->a);
|
||||
$this->http_custom_headers = $this->v('http_custom_headers', '', $this->a);
|
||||
$this->max_redirects = $this->v('max_redirects', 3, $this->a);
|
||||
$this->format = $this->v('format', false, $this->a);
|
||||
$this->redirects = array();
|
||||
$this->stream_id = '';
|
||||
$this->timeout = $this->v('reader_timeout', 30, $this->a);
|
||||
$this->response_headers = array();
|
||||
$this->digest_auth = 0;
|
||||
$this->auth_infos = $this->v('reader_auth_infos', array(), $this->a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function setHTTPMethod($v) {
|
||||
$this->http_method = $v;
|
||||
}
|
||||
|
||||
function setMessageBody($v) {
|
||||
$this->message_body = $v;
|
||||
}
|
||||
|
||||
function setAcceptHeader($v) {
|
||||
$this->http_accept_header = $v;
|
||||
}
|
||||
|
||||
function setCustomHeaders($v) {
|
||||
$this->http_custom_headers = $v;
|
||||
}
|
||||
|
||||
function addCustomHeaders($v) {
|
||||
if ($this->http_custom_headers) $this->http_custom_headers .= "\r\n";
|
||||
$this->http_custom_headers .= $v;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function activate($path, $data = '', $ping_only = 0, $timeout = 0) {
|
||||
$this->setCredentials($path);
|
||||
$this->ping_only = $ping_only;
|
||||
if ($timeout) $this->timeout = $timeout;
|
||||
$id = md5($path . ' ' . $data);
|
||||
if ($this->stream_id != $id) {
|
||||
$this->stream_id = $id;
|
||||
$this->base = $this->calcBase($path);
|
||||
$this->uri = $this->calcURI($path, $this->base);
|
||||
$this->stream = ($data) ? $this->getDataStream($data) : $this->getSocketStream($this->base, $ping_only);
|
||||
if ($this->stream && !$this->ping_only) {
|
||||
$this->getFormat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setCredentials($url) {
|
||||
if (!$creds = $this->v('arc_reader_credentials', array(), $this->a)) return 0;
|
||||
foreach ($creds as $pattern => $cred) {
|
||||
$regex = '/' . preg_replace('/([\:\/\.\?])/', '\\\\\1', $pattern) . '/';
|
||||
if (!preg_match($regex, $url)) continue;
|
||||
$parts = parse_url($url);
|
||||
$path = $this->v1('path', '/', $parts);
|
||||
/* Basic auth */
|
||||
$auth = 'Basic ' . base64_encode($cred);
|
||||
/* Digest auth */
|
||||
if (preg_match('/(.*)\:\:(.*)/', $cred, $m)) {
|
||||
$username = $m[1];
|
||||
$pwd = $m[2];
|
||||
$auth = '';
|
||||
$hs = $this->getResponseHeaders();
|
||||
/* 401 received */
|
||||
$h = $this->v('www-authenticate', '', $hs);
|
||||
if ($h && preg_match('/Digest/i', $h)) {
|
||||
$auth = 'Digest ';
|
||||
/* Digest realm="$realm", nonce="$nonce", qop="auth", opaque="$opaque" */
|
||||
$ks = array('realm', 'nonce', 'opaque');/* skipping qop, assuming "auth" */
|
||||
foreach ($ks as $i => $k) {
|
||||
$$k = preg_match('/' . $k . '=\"?([^\"]+)\"?/i', $h, $m) ? $m[1] : '';
|
||||
$auth .= ($i ? ', ' : '') . $k . '="' . $$k . '"';
|
||||
$this->auth_infos[$k] = $$k;
|
||||
}
|
||||
$this->auth_infos['auth'] = $auth;
|
||||
$this->auth_infos['request_count'] = 1;
|
||||
}
|
||||
/* 401 or repeated request */
|
||||
if ($this->v('auth', 0, $this->auth_infos)) {
|
||||
$qop = 'auth';
|
||||
$auth = $this->auth_infos['auth'];
|
||||
$rc = $this->auth_infos['request_count'];
|
||||
$realm = $this->auth_infos['realm'];
|
||||
$nonce = $this->auth_infos['nonce'];
|
||||
$ha1 = md5($username . ':' . $realm . ':' . $pwd);
|
||||
$ha2 = md5($this->http_method . ':' . $path);
|
||||
$nc = dechex($rc);
|
||||
$cnonce = dechex($rc * 2);
|
||||
$resp = md5($ha1 . ':' . $nonce . ':' . $nc . ':' . $cnonce . ':' . $qop . ':' . $ha2);
|
||||
$auth .= ', username="' . $username . '"' .
|
||||
', uri="' . $path . '"' .
|
||||
', qop=' . $qop . '' .
|
||||
', nc=' . $nc .
|
||||
', cnonce="' . $cnonce . '"' .
|
||||
', uri="' . $path . '"' .
|
||||
', response="' . $resp . '"' .
|
||||
'';
|
||||
$this->auth_infos['request_count'] = $rc + 1;
|
||||
}
|
||||
}
|
||||
/* add header */
|
||||
if ($auth) {
|
||||
$this->setCustomHeaders('Authorization: ' . $auth);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function useProxy($url) {
|
||||
if (!$this->v1('proxy_host', 0, $this->a)) {
|
||||
return false;
|
||||
}
|
||||
$skips = $this->v1('proxy_skip', array(), $this->a);
|
||||
foreach ($skips as $skip) {
|
||||
if (strpos($url, $skip) !== false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function createStream($path, $data = '') {
|
||||
$this->base = $this->calcBase($path);
|
||||
$this->stream = ($data) ? $this->getDataStream($data) : $this->getSocketStream($this->base);
|
||||
}
|
||||
|
||||
function getDataStream($data) {
|
||||
return array('type' => 'data', 'pos' => 0, 'headers' => array(), 'size' => strlen($data), 'data' => $data, 'buffer' => '');
|
||||
}
|
||||
|
||||
function getSocketStream($url) {
|
||||
if ($url == 'file://') {
|
||||
return $this->addError('Error: file does not exists or is not accessible');
|
||||
}
|
||||
$parts = parse_url($url);
|
||||
$mappings = array('file' => 'File', 'http' => 'HTTP', 'https' => 'HTTP');
|
||||
if ($scheme = $this->v(strtolower($parts['scheme']), '', $mappings)) {
|
||||
return $this->m('get' . $scheme . 'Socket', $url, $this->getDataStream(''));
|
||||
}
|
||||
}
|
||||
|
||||
function getFileSocket($url) {
|
||||
$parts = parse_url($url);
|
||||
$s = file_exists($parts['path']) ? @fopen($parts['path'], 'rb') : false;
|
||||
if (!$s) {
|
||||
return $this->addError('Socket error: Could not open "' . $parts['path'] . '"');
|
||||
}
|
||||
return array('type' => 'socket', 'socket' =>& $s, 'headers' => array(), 'pos' => 0, 'size' => filesize($parts['path']), 'buffer' => '');
|
||||
}
|
||||
|
||||
function getHTTPSocket($url, $redirs = 0) {
|
||||
$parts = parse_url($url);
|
||||
if (!isset($parts['scheme'])) {
|
||||
return $this->addError('Socket error: No supported URI scheme detected.');
|
||||
}
|
||||
$parts['port'] = ($parts['scheme'] == 'https') ? $this->v1('port', 443, $parts) : $this->v1('port', 80, $parts);
|
||||
$nl = "\r\n";
|
||||
$http_mthd = strtoupper($this->http_method);
|
||||
if ($this->v1('user', 0, $parts) || $this->useProxy($url)) {
|
||||
$h_code = $http_mthd . ' ' . $url;
|
||||
}
|
||||
else {
|
||||
$h_code = $http_mthd . ' ' . $this->v1('path', '/', $parts) . (($v = $this->v1('query', 0, $parts)) ? '?' . $v : '') . (($v = $this->v1('fragment', 0, $parts)) ? '#' . $v : '');
|
||||
}
|
||||
$h_code .= ' HTTP/1.0' . $nl.
|
||||
'Host: ' . $parts['host'] . ':' . $parts['port'] . $nl .
|
||||
(($v = $this->http_accept_header) ? $v . $nl : '') .
|
||||
(($v = $this->http_user_agent_header) && !preg_match('/User\-Agent\:/', $this->http_custom_headers) ? $v . $nl : '') .
|
||||
(($http_mthd == 'POST') ? 'Content-Length: ' . strlen($this->message_body) . $nl : '') .
|
||||
($this->http_custom_headers ? trim($this->http_custom_headers) . $nl : '') .
|
||||
$nl .
|
||||
'';
|
||||
/* post body */
|
||||
if ($http_mthd == 'POST') {
|
||||
$h_code .= $this->message_body . $nl;
|
||||
}
|
||||
/* connect */
|
||||
if ($this->useProxy($url)) {
|
||||
$s = @fsockopen($this->a['proxy_host'], $this->a['proxy_port'], $errno, $errstr, $this->timeout);
|
||||
}
|
||||
elseif (($parts['scheme'] == 'https') && function_exists('stream_socket_client')) {
|
||||
// SSL options via config array, code by Hannes Muehleisen (muehleis@informatik.hu-berlin.de)
|
||||
$context = stream_context_create();
|
||||
foreach ($this->a as $k => $v) {
|
||||
if (preg_match('/^arc_reader_ssl_(.+)$/', $k, $m)) {
|
||||
stream_context_set_option($context, 'ssl', $m[1], $v);
|
||||
}
|
||||
}
|
||||
$s = stream_socket_client('ssl://' . $parts['host'] . ':' . $parts['port'], $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT, $context);
|
||||
}
|
||||
elseif ($parts['scheme'] == 'https') {
|
||||
$s = @fsockopen('ssl://' . $parts['host'], $parts['port'], $errno, $errstr, $this->timeout);
|
||||
}
|
||||
elseif ($parts['scheme'] == 'http') {
|
||||
$s = @fsockopen($parts['host'], $parts['port'], $errno, $errstr, $this->timeout);
|
||||
}
|
||||
if (!$s) {
|
||||
return $this->addError('Socket error: Could not connect to "' . $url . '" (proxy: ' . ($this->useProxy($url) ? '1' : '0') . '): ' . $errstr);
|
||||
}
|
||||
/* request */
|
||||
fwrite($s, $h_code);
|
||||
/* timeout */
|
||||
if ($this->timeout) {
|
||||
//stream_set_blocking($s, false);
|
||||
stream_set_timeout($s, $this->timeout);
|
||||
}
|
||||
/* response headers */
|
||||
$h = array();
|
||||
$this->response_headers = $h;
|
||||
if (!$this->ping_only) {
|
||||
do {
|
||||
$line = trim(fgets($s, 4096));
|
||||
$info = stream_get_meta_data($s);
|
||||
if (preg_match("/^HTTP[^\s]+\s+([0-9]{1})([0-9]{2})(.*)$/i", $line, $m)) {/* response code */
|
||||
$error = in_array($m[1], array('4', '5')) ? $m[1] . $m[2] . ' ' . $m[3] : '';
|
||||
$error = ($m[1].$m[2] == '304') ? '304 '.$m[3] : $error;
|
||||
$h['response-code'] = $m[1] . $m[2];
|
||||
$h['error'] = $error;
|
||||
$h['redirect'] = ($m[1] == '3') ? true : false;
|
||||
}
|
||||
elseif (preg_match('/^([^\:]+)\:\s*(.*)$/', $line, $m)) {/* header */
|
||||
$h_name = strtolower($m[1]);
|
||||
if (!isset($h[$h_name])) {/* 1st value */
|
||||
$h[$h_name] = trim($m[2]);
|
||||
}
|
||||
elseif (!is_array($h[$h_name])) {/* 2nd value */
|
||||
$h[$h_name] = array($h[$h_name], trim($m[2]));
|
||||
}
|
||||
else {/* more values */
|
||||
$h[$h_name][] = trim($m[2]);
|
||||
}
|
||||
}
|
||||
} while(!$info['timed_out'] && !feof($s) && $line);
|
||||
$h['format'] = strtolower(preg_replace('/^([^\s]+).*$/', '\\1', $this->v('content-type', '', $h)));
|
||||
$h['encoding'] = preg_match('/(utf\-8|iso\-8859\-1|us\-ascii)/', $this->v('content-type', '', $h), $m) ? strtoupper($m[1]) : '';
|
||||
$h['encoding'] = preg_match('/charset=\s*([^\s]+)/si', $this->v('content-type', '', $h), $m) ? strtoupper($m[1]) : $h['encoding'];
|
||||
$this->response_headers = $h;
|
||||
/* result */
|
||||
if ($info['timed_out']) {
|
||||
return $this->addError('Connection timed out after ' . $this->timeout . ' seconds');
|
||||
}
|
||||
/* error */
|
||||
if ($v = $this->v('error', 0, $h)) {
|
||||
/* digest auth */
|
||||
/* 401 received */
|
||||
if (preg_match('/Digest/i', $this->v('www-authenticate', '', $h)) && !$this->digest_auth) {
|
||||
$this->setCredentials($url);
|
||||
$this->digest_auth = 1;
|
||||
return $this->getHTTPSocket($url);
|
||||
}
|
||||
return $this->addError($error . ' "' . (!feof($s) ? trim(strip_tags(fread($s, 64))) . '..."' : ''));
|
||||
}
|
||||
/* redirect */
|
||||
if ($this->v('redirect', 0, $h) && ($new_url = $this->v1('location', 0, $h))) {
|
||||
fclose($s);
|
||||
$this->redirects[$url] = $new_url;
|
||||
$this->base = $new_url;
|
||||
if ($redirs > $this->max_redirects) {
|
||||
return $this->addError('Max numbers of redirects exceeded.');
|
||||
}
|
||||
return $this->getHTTPSocket($new_url, $redirs+1);
|
||||
}
|
||||
}
|
||||
if ($this->timeout) {
|
||||
stream_set_blocking($s, true);
|
||||
}
|
||||
return array('type' => 'socket', 'url' => $url, 'socket' =>& $s, 'headers' => $h, 'pos' => 0, 'size' => $this->v('content-length', 0, $h), 'buffer' => '');
|
||||
}
|
||||
|
||||
function readStream($buffer_xml = true, $d_size = 1024) {
|
||||
//if (!$s = $this->v('stream')) return '';
|
||||
if (!$s = $this->v('stream')) return $this->addError('missing stream in "readStream" ' . $this->uri);
|
||||
$s_type = $this->v('type', '', $s);
|
||||
$r = $s['buffer'];
|
||||
$s['buffer'] = '';
|
||||
if ($s['size']) $d_size = min($d_size, $s['size'] - $s['pos']);
|
||||
/* data */
|
||||
if ($s_type == 'data') {
|
||||
$d = ($d_size > 0) ? substr($s['data'], $s['pos'], $d_size) : '';
|
||||
}
|
||||
/* socket */
|
||||
elseif ($s_type == 'socket') {
|
||||
$d = ($d_size > 0) && !feof($s['socket']) ? fread($s['socket'], $d_size) : '';
|
||||
}
|
||||
$eof = $d ? false : true;
|
||||
/* chunked despite HTTP 1.0 request */
|
||||
if (isset($s['headers']) && isset($s['headers']['transfer-encoding']) && ($s['headers']['transfer-encoding'] == 'chunked')) {
|
||||
$d = preg_replace('/(^|[\r\n]+)[0-9a-f]{1,4}[\r\n]+/', '', $d);
|
||||
}
|
||||
$s['pos'] += strlen($d);
|
||||
if ($buffer_xml) {/* stop after last closing xml tag (if available) */
|
||||
if (preg_match('/^(.*\>)([^\>]*)$/s', $d, $m)) {
|
||||
$d = $m[1];
|
||||
$s['buffer'] = $m[2];
|
||||
}
|
||||
elseif (!$eof) {
|
||||
$s['buffer'] = $r . $d;
|
||||
$this->stream = $s;
|
||||
return $this->readStream(true, $d_size);
|
||||
}
|
||||
}
|
||||
$this->stream = $s;
|
||||
return $r . $d;
|
||||
}
|
||||
|
||||
function closeStream() {
|
||||
if (isset($this->stream)) {
|
||||
if ($this->v('type', 0, $this->stream) == 'socket') {
|
||||
@fclose($this->stream['socket']);
|
||||
}
|
||||
unset($this->stream);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getFormat() {
|
||||
if (!$this->format) {
|
||||
if (!$this->v('stream')) {
|
||||
return $this->addError('missing stream in "getFormat"');
|
||||
}
|
||||
$v = $this->readStream(false);
|
||||
$mtype = $this->v('format', '', $this->stream['headers']);
|
||||
$this->stream['buffer'] = $v . $this->stream['buffer'];
|
||||
$ext = preg_match('/\.([^\.]+)$/', $this->uri, $m) ? $m[1] : '';
|
||||
$this->format = ARC2::getFormat($v, $mtype, $ext);
|
||||
}
|
||||
return $this->format;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getResponseHeaders() {
|
||||
if (isset($this->stream) && isset($this->stream['headers'])) {
|
||||
return $this->stream['headers'];
|
||||
}
|
||||
return $this->response_headers;
|
||||
}
|
||||
|
||||
function getEncoding($default = 'UTF-8') {
|
||||
return $this->v1('encoding', $default, $this->stream['headers']);
|
||||
}
|
||||
|
||||
function getRedirects() {
|
||||
return $this->redirects;
|
||||
}
|
||||
|
||||
function getAuthInfos() {
|
||||
return $this->auth_infos;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
121
arc/ARC2_Resource.php
Normal file
121
arc/ARC2_Resource.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 Resource object
|
||||
*
|
||||
* @author Benjamin Nowack <bnowack@semsol.com>
|
||||
* @license http://arc.semsol.org/license
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-11-26
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_Resource extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_Resource($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->uri = '';
|
||||
$this->index = array();
|
||||
$this->fetched = array();
|
||||
$this->store = '';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function setURI($uri) {
|
||||
$this->uri = $uri;
|
||||
}
|
||||
|
||||
function setIndex($index) {
|
||||
$this->index = $index;
|
||||
}
|
||||
|
||||
function setProps($props, $s = '') {
|
||||
if (!$s) $s = $this->uri;
|
||||
$this->index[$s] = $props;
|
||||
}
|
||||
|
||||
function setProp($p, $os, $s = '') {
|
||||
if (!$s) $s = $this->uri;
|
||||
/* single plain value */
|
||||
if (!is_array($os)) $os = array('value' => $os, 'type' => 'literal');
|
||||
/* single array value */
|
||||
if (isset($os['value'])) $os = array($os);
|
||||
/* list of values */
|
||||
foreach ($os as $i => $o) {
|
||||
if (!is_array($o)) $os[i] = array('value' => $o, 'type' => 'literal');
|
||||
}
|
||||
$this->index[$s][$this->expandPName($p)] = $os;
|
||||
}
|
||||
|
||||
function setStore($store) {
|
||||
$this->store = $store;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function fetchData($uri = '') {
|
||||
if (!$uri) $uri = $this->uri;
|
||||
if (!$uri) return 0;
|
||||
if (in_array($uri, $this->fetched)) return 0;
|
||||
$this->index[$uri] = array();
|
||||
if ($this->store) {
|
||||
$index = $this->store->query('DESCRIBE <' . $uri . '>', 'raw');
|
||||
}
|
||||
else {
|
||||
$index = $this->toIndex($uri);
|
||||
}
|
||||
$this->index = ARC2::getMergedIndex($this->index, $index);
|
||||
$this->fetched[] = $uri;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getProps($p = '', $s = '') {
|
||||
if (!$s) $s = $this->uri;
|
||||
if (!$s) return array();
|
||||
if (!isset($this->index[$s])) $this->fetchData($s);
|
||||
if (!$p) return $this->index[$s];
|
||||
return $this->v($this->expandPName($p), array(), $this->index[$s]);
|
||||
}
|
||||
|
||||
function getProp($p, $s = '') {
|
||||
$props = $this->getProps($p, $s);
|
||||
return $props ? $props[0] : '';
|
||||
}
|
||||
|
||||
function getPropValue($p, $s = '') {
|
||||
$prop = $this->getProp($p, $s);
|
||||
return $prop ? $prop['value'] : '';
|
||||
}
|
||||
|
||||
function getPropValues($p, $s = '') {
|
||||
$r = array();
|
||||
$props = $this->getProps($p, $s);
|
||||
foreach ($props as $prop) {
|
||||
$r[] = $prop['value'];
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function hasPropValue($p, $o, $s = '') {
|
||||
$props = $this->getProps($p, $s);
|
||||
$o = $this->expandPName($o);
|
||||
foreach ($props as $prop) {
|
||||
if ($prop['value'] == $o) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
67
arc/ARC2_getFormat.php
Normal file
67
arc/ARC2_getFormat.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 format detection function
|
||||
*
|
||||
* @author Benjamin Nowack <bnowack@semsol.com>
|
||||
* @license http://arc.semsol.org/license
|
||||
* @package ARC2
|
||||
* @version 2009-10-16
|
||||
*/
|
||||
|
||||
function ARC2_getFormat($v, $mtype = '', $ext = '') {
|
||||
$r = false;
|
||||
/* mtype check (atom, rdf/xml, turtle, n3, mp3, jpg) */
|
||||
$r = (!$r && preg_match('/\/atom\+xml/', $mtype)) ? 'atom' : $r;
|
||||
$r = (!$r && preg_match('/\/rdf\+xml/', $mtype)) ? 'rdfxml' : $r;
|
||||
$r = (!$r && preg_match('/\/(x\-)?turtle/', $mtype)) ? 'turtle' : $r;
|
||||
$r = (!$r && preg_match('/\/rdf\+n3/', $mtype)) ? 'n3' : $r;
|
||||
/* xml sniffing */
|
||||
if (
|
||||
!$r &&
|
||||
/* starts with angle brackets */
|
||||
preg_match('/^\s*\<[^\s]/s', $v) &&
|
||||
/* has an xmlns:* declaration or a matching pair of tags */
|
||||
(preg_match('/\sxmlns\:?/', $v) || preg_match('/\<([^\s]+).+\<\/\\1\>/s', $v)) &&
|
||||
/* not a typical ntriples/turtle/n3 file */
|
||||
!preg_match('/\.\s*$/s', $v)
|
||||
) {
|
||||
while (preg_match('/^\s*\<\?xml[^\r\n]+\?\>\s*/s', $v)) {
|
||||
$v = preg_replace('/^\s*\<\?xml[^\r\n]+\?\>\s*/s', '', $v);
|
||||
}
|
||||
while (preg_match('/^\s*\<\!--.+?--\>\s*/s', $v)) {
|
||||
$v = preg_replace('/^\s*\<\!--.+?--\>\s*/s', '', $v);
|
||||
}
|
||||
/* doctype checks (html, rdf) */
|
||||
$r = (!$r && preg_match('/^\s*\<\!DOCTYPE\s+html[\s|\>]/is', $v)) ? 'html' : $r;
|
||||
$r = (!$r && preg_match('/^\s*\<\!DOCTYPE\s+[a-z0-9\_\-]\:RDF\s/is', $v)) ? 'rdfxml' : $r;
|
||||
/* markup checks */
|
||||
$v = preg_replace('/^\s*\<\!DOCTYPE\s.*\]\>/is', '', $v);
|
||||
$r = (!$r && preg_match('/^\s*\<rss\s+[^\>]*version/s', $v)) ? 'rss' : $r;
|
||||
$r = (!$r && preg_match('/^\s*\<feed\s+[^\>]+http\:\/\/www\.w3\.org\/2005\/Atom/s', $v)) ? 'atom' : $r;
|
||||
$r = (!$r && preg_match('/^\s*\<opml\s/s', $v)) ? 'opml' : $r;
|
||||
$r = (!$r && preg_match('/^\s*\<html[\s|\>]/is', $v)) ? 'html' : $r;
|
||||
$r = (!$r && preg_match('/^\s*\<sparql\s+[^\>]+http\:\/\/www\.w3\.org\/2005\/sparql\-results\#/s', $v)) ? 'sparqlxml' : $r;
|
||||
$r = (!$r && preg_match('/^\s*\<[^\>]+http\:\/\/www\.w3\.org\/2005\/sparql\-results#/s', $v)) ? 'srx' : $r;
|
||||
$r = (!$r && preg_match('/^\s*\<[^\s]*RDF[\s\>]/s', $v)) ? 'rdfxml' : $r;
|
||||
$r = (!$r && preg_match('/^\s*\<[^\>]+http\:\/\/www\.w3\.org\/1999\/02\/22\-rdf/s', $v)) ? 'rdfxml' : $r;
|
||||
|
||||
$r = !$r ? 'xml' : $r;
|
||||
}
|
||||
/* json|jsonp */
|
||||
if (!$r && preg_match('/^[a-z0-9\.\(]*\s*[\{\[].*/s', trim($v))) {
|
||||
/* google social graph api */
|
||||
$r = (!$r && preg_match('/\"canonical_mapping\"/', $v)) ? 'sgajson' : $r;
|
||||
/* crunchbase api */
|
||||
$r = (!$r && preg_match('/\"permalink\"/', $v)) ? 'cbjson' : $r;
|
||||
|
||||
$r = !$r ? 'json' : $r;
|
||||
}
|
||||
/* turtle/n3 */
|
||||
$r = (!$r && preg_match('/\@(prefix|base)/i', $v)) ? 'turtle' : $r;
|
||||
$r = (!$r && preg_match('/^(ttl)$/', $ext)) ? 'turtle' : $r;
|
||||
$r = (!$r && preg_match('/^(n3)$/', $ext)) ? 'n3' : $r;
|
||||
/* ntriples */
|
||||
$r = (!$r && preg_match('/^\s*(_:|<).+?\s+<[^>]+?>\s+\S.+?\s*\.\s*$/sm', $v)) ? 'ntriples' : $r;
|
||||
$r = (!$r && preg_match('/^(nt)$/', $ext)) ? 'ntriples' : $r;
|
||||
return $r;
|
||||
}
|
||||
47
arc/ARC2_getPreferredFormat.php
Normal file
47
arc/ARC2_getPreferredFormat.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
function: result format detection
|
||||
author: Benjamin Nowack
|
||||
version: 2008-08-04
|
||||
*/
|
||||
|
||||
function ARC2_getPreferredFormat($default = 'plain') {
|
||||
$formats = array(
|
||||
'html' => 'HTML', 'text/html' => 'HTML', 'xhtml+xml' => 'HTML',
|
||||
'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML',
|
||||
'ntriples' => 'NTriples', 'rdf+n3' => 'Turtle', 'x-turtle' => 'Turtle', 'turtle' => 'Turtle',
|
||||
'rdfjson' => 'RDFJSON', 'json' => 'RDFJSON',
|
||||
'xml' => 'XML',
|
||||
'legacyjson' => 'LegacyJSON'
|
||||
);
|
||||
$prefs = array();
|
||||
$o_vals = array();
|
||||
/* accept header */
|
||||
if ($vals = explode(',', $_SERVER['HTTP_ACCEPT'])) {
|
||||
foreach ($vals as $val) {
|
||||
if (preg_match('/(rdf\+n3|x\-turtle|rdf\+xml|text\/html|xhtml\+xml|xml|json)/', $val, $m)) {
|
||||
$o_vals[$m[1]] = 1;
|
||||
if (preg_match('/\;q\=([0-9\.]+)/', $val, $sub_m)) {
|
||||
$o_vals[$m[1]] = 1 * $sub_m[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* arg */
|
||||
if (isset($_GET['format'])) $o_vals[$_GET['format']] = 1.1;
|
||||
/* rank */
|
||||
arsort($o_vals);
|
||||
foreach ($o_vals as $val => $prio) {
|
||||
$prefs[] = $val;
|
||||
}
|
||||
/* default */
|
||||
$prefs[] = $default;
|
||||
foreach ($prefs as $pref) {
|
||||
if (isset($formats[$pref])) {
|
||||
return $formats[$pref];
|
||||
}
|
||||
}
|
||||
}
|
||||
84
arc/extractors/ARC2_DcExtractor.php
Normal file
84
arc/extractors/ARC2_DcExtractor.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 DC Extractor
|
||||
author: Benjamin Nowack
|
||||
version: 2008-04-09 (Fix: base URL (not doc URL) was used for annotations)
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFExtractor');
|
||||
|
||||
class ARC2_DcExtractor extends ARC2_RDFExtractor {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_DcExtractor($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->a['ns']['dc'] = 'http://purl.org/dc/elements/1.1/';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractRDF() {
|
||||
$t_vals = array();
|
||||
$t = '';
|
||||
foreach ($this->nodes as $n) {
|
||||
foreach (array('title', 'link', 'meta') as $tag) {
|
||||
if ($n['tag'] == $tag) {
|
||||
$m = 'extract' . ucfirst($tag);
|
||||
list ($t_vals, $t) = $this->$m($n, $t_vals, $t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($t) {
|
||||
$doc = $this->getFilledTemplate($t, $t_vals, $n['doc_base']);
|
||||
$this->addTs(ARC2::getTriplesFromIndex($doc));
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractTitle($n, $t_vals, $t) {
|
||||
if ($t_vals['title'] = $this->getPlainContent($n)) {
|
||||
$t .= '<' . $n['doc_url'] . '> dc:title ?title . ';
|
||||
}
|
||||
return array($t_vals, $t);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractLink($n, $t_vals, $t) {
|
||||
if ($this->hasRel($n, 'alternate') || $this->hasRel($n, 'meta')) {
|
||||
if ($href = $this->v('href uri', '', $n['a'])) {
|
||||
$t .= '<' . $n['doc_url'] . '> rdfs:seeAlso <' . $href . '> . ';
|
||||
if ($v = $this->v('type', '', $n['a'])) {
|
||||
$t .= '<' .$href. '> dc:format "' . $v . '" . ';
|
||||
}
|
||||
if ($v = $this->v('title', '', $n['a'])) {
|
||||
$t .= '<' .$href. '> dc:title "' . $v . '" . ';
|
||||
}
|
||||
}
|
||||
}
|
||||
return array($t_vals, $t);
|
||||
}
|
||||
|
||||
function extractMeta($n, $t_vals, $t) {
|
||||
if ($this->hasAttribute('http-equiv', $n, 'Content-Type') || $this->hasAttribute('http-equiv', $n, 'content-type')) {
|
||||
if ($v = $this->v('content', '', $n['a'])) {
|
||||
$t .= '<' . $n['doc_url'] . '> dc:format "' . $v . '" . ';
|
||||
}
|
||||
}
|
||||
return array($t_vals, $t);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
288
arc/extractors/ARC2_ErdfExtractor.php
Normal file
288
arc/extractors/ARC2_ErdfExtractor.php
Normal file
@@ -0,0 +1,288 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 eRDF Extractor (w/o link title generation)
|
||||
author: Benjamin Nowack
|
||||
version: 2009-02-09 (Tweak: getRootNode returns 1st node if html tag is not found)
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFExtractor');
|
||||
|
||||
class ARC2_ErdfExtractor extends ARC2_RDFExtractor {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_ErdfExtractor($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractRDF() {
|
||||
if (!isset($this->caller->detected_formats['erdf'])) return 0;
|
||||
$root_node = $this->getRootNode();
|
||||
$base = $this->getDocBase();
|
||||
$ns = $this->getNamespaces();
|
||||
$context = array(
|
||||
'base' => $base,
|
||||
'prev_res' => $base,
|
||||
'cur_res' => $base,
|
||||
'ns' => $ns,
|
||||
'lang' => '',
|
||||
);
|
||||
$this->processNode($root_node, $context);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getRootNode() {
|
||||
foreach ($this->nodes as $id => $node) {
|
||||
if ($node['tag'] == 'html') {
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
return $this->nodes[0];
|
||||
}
|
||||
|
||||
function getNamespaces() {
|
||||
$r = array(
|
||||
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
||||
'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#'
|
||||
);
|
||||
foreach ($this->nodes as $id => $node) {
|
||||
if (preg_match('/^(link|a)$/', $node['tag']) && isset($node['a']['rel']) && preg_match('/schema\.([^\s]+)/is', $node['a']['rel'], $m) && isset($node['a']['href uri'])) {
|
||||
$r[$m[1]] = $node['a']['href uri'];
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processNode($n, $ct) {
|
||||
/* context */
|
||||
//$ct['lang'] = $this->v('xml:lang', $ct['lang'], $n['a']);
|
||||
$ct['lang'] = '';
|
||||
$ct['prop_uris'] = $this->getPropertyURIs($n, $ct);
|
||||
$ct['prev_res'] = $ct['cur_res'];
|
||||
$ct['cur_res'] = $this->getCurrentResourceURI($n, $ct);
|
||||
$ct['cur_obj_id'] = $this->getCurrentObjectID($n, $ct);
|
||||
$ct['cur_obj_literal'] = $this->getCurrentObjectLiteral($n, $ct);
|
||||
/* triple production (http://research.talis.com/2005/erdf/wiki/Main/SummaryOfTripleProductionRules) */
|
||||
foreach ($ct['prop_uris'] as $type => $uris) {
|
||||
foreach ($uris as $uri) {
|
||||
$rdf_type = preg_match('/^ /', $uri) ? 1 : 0;
|
||||
/* meta + name */
|
||||
if (($type == 'name') && ($n['tag'] == 'meta')) {
|
||||
$t = array(
|
||||
's' => $ct['cur_res'],
|
||||
's_type' => 'uri',
|
||||
'p' => $uri,
|
||||
'o' => $ct['cur_obj_literal']['value'],
|
||||
'o_type' => 'literal',
|
||||
'o_lang' => $ct['cur_obj_literal']['datatype'] ? '' : $ct['cur_obj_literal']['lang'],
|
||||
'o_datatype' => $ct['cur_obj_literal']['datatype'],
|
||||
);
|
||||
$this->addT($t);
|
||||
}
|
||||
/* class */
|
||||
if ($type == 'class') {
|
||||
if ($rdf_type) {
|
||||
$s = $this->v('href uri', $ct['cur_res'], $n['a']);
|
||||
$s = $this->v('src uri', $s, $n['a']);
|
||||
$t = array(
|
||||
's' => $s,
|
||||
's_type' => 'uri',
|
||||
'p' => $ct['ns']['rdf'] . 'type',
|
||||
'o' => trim($uri),
|
||||
'o_type' => 'uri',
|
||||
'o_lang' => '',
|
||||
'o_datatype' => '',
|
||||
);
|
||||
}
|
||||
elseif (isset($n['a']['id'])) {/* used as object */
|
||||
$t = array(
|
||||
's' => $ct['prev_res'],
|
||||
's_type' => 'uri',
|
||||
'p' => $uri,
|
||||
'o' => $ct['cur_res'],
|
||||
'o_type' => 'uri',
|
||||
'o_lang' => '',
|
||||
'o_datatype' => '',
|
||||
);
|
||||
}
|
||||
else {
|
||||
$t = array(
|
||||
's' => $ct['cur_res'],
|
||||
's_type' => 'uri',
|
||||
'p' => $uri,
|
||||
'o' => $ct['cur_obj_literal']['value'],
|
||||
'o_type' => 'literal',
|
||||
'o_lang' => $ct['cur_obj_literal']['datatype'] ? '' : $ct['cur_obj_literal']['lang'],
|
||||
'o_datatype' => $ct['cur_obj_literal']['datatype'],
|
||||
);
|
||||
if (($o = $this->v('src uri', '', $n['a'])) || ($o = $this->v('href uri', '', $n['a']))) {
|
||||
if (!$ct['prop_uris']['rel'] && !$ct['prop_uris']['rev']) {
|
||||
$t['o'] = $o;
|
||||
$t['o_type'] = 'uri';
|
||||
$t['o_lang'] = '';
|
||||
$t['o_datatype'] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->addT($t);
|
||||
}
|
||||
/* rel */
|
||||
if ($type == 'rel') {
|
||||
if (($o = $this->v('src uri', '', $n['a'])) || ($o = $this->v('href uri', '', $n['a']))) {
|
||||
$t = array(
|
||||
's' => $ct['cur_res'],
|
||||
's_type' => 'uri',
|
||||
'p' => $uri,
|
||||
'o' => $o,
|
||||
'o_type' => 'uri',
|
||||
'o_lang' => '',
|
||||
'o_datatype' => '',
|
||||
);
|
||||
$this->addT($t);
|
||||
}
|
||||
}
|
||||
/* rev */
|
||||
if ($type == 'rev') {
|
||||
if (($s = $this->v('src uri', '', $n['a'])) || ($s = $this->v('href uri', '', $n['a']))) {
|
||||
$t = array(
|
||||
's' => $s,
|
||||
's_type' => 'uri',
|
||||
'p' => $uri,
|
||||
'o' => $ct['cur_res'],
|
||||
'o_type' => 'uri',
|
||||
'o_lang' => '',
|
||||
'o_datatype' => '',
|
||||
);
|
||||
$this->addT($t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* imgs */
|
||||
if ($n['tag'] == 'img') {
|
||||
if (($s = $this->v('src uri', '', $n['a'])) && $ct['cur_obj_literal']['value']) {
|
||||
$t = array(
|
||||
's' => $s,
|
||||
's_type' => 'uri',
|
||||
'p' => $ct['ns']['rdfs'] . 'label',
|
||||
'o' => $ct['cur_obj_literal']['value'],
|
||||
'o_type' => 'literal',
|
||||
'o_lang' => $ct['cur_obj_literal']['datatype'] ? '' : $ct['cur_obj_literal']['lang'],
|
||||
'o_datatype' => $ct['cur_obj_literal']['datatype'],
|
||||
);
|
||||
$this->addT($t);
|
||||
}
|
||||
}
|
||||
/* anchors */
|
||||
if ($n['tag'] == 'a') {
|
||||
if (($s = $this->v('href uri', '', $n['a'])) && $ct['cur_obj_literal']['value']) {
|
||||
$t = array(
|
||||
's' => $s,
|
||||
's_type' => 'uri',
|
||||
'p' => $ct['ns']['rdfs'] . 'label',
|
||||
'o' => $ct['cur_obj_literal']['value'],
|
||||
'o_type' => 'literal',
|
||||
'o_lang' => $ct['cur_obj_literal']['datatype'] ? '' : $ct['cur_obj_literal']['lang'],
|
||||
'o_datatype' => $ct['cur_obj_literal']['datatype'],
|
||||
);
|
||||
$this->addT($t);
|
||||
}
|
||||
}
|
||||
/* recurse */
|
||||
if ($n['tag'] == 'a') {
|
||||
$ct['cur_res'] = $ct['cur_obj_id'];
|
||||
}
|
||||
$sub_nodes = $this->getSubNodes($n);
|
||||
foreach ($sub_nodes as $sub_node) {
|
||||
$this->processNode($sub_node, $ct);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getPropertyURIs($n, $ct) {
|
||||
$r = array();
|
||||
foreach (array('rel', 'rev', 'class', 'name', 'src') as $type) {
|
||||
$r[$type] = array();
|
||||
$vals = $this->v($type . ' m', array(), $n['a']);
|
||||
foreach ($vals as $val) {
|
||||
if (!trim($val)) continue;
|
||||
list($uri, $sub_v) = $this->xQname(trim($val, '- '), $ct['base'], $ct['ns'], $type);
|
||||
if (!$uri) continue;
|
||||
$rdf_type = preg_match('/^-/', trim($val)) ? 1 : 0;
|
||||
$r[$type][] = $rdf_type ? ' ' . $uri : $uri;
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getCurrentResourceURI($n, $ct) {
|
||||
if (isset($n['a']['id'])) {
|
||||
list($r, $sub_v) = $this->xURI('#' . $n['a']['id'], $ct['base'], $ct['ns']);
|
||||
return $r;
|
||||
}
|
||||
return $ct['cur_res'];
|
||||
}
|
||||
|
||||
function getCurrentObjectID($n, $ct) {
|
||||
foreach (array('href', 'src') as $a) {
|
||||
if (isset($n['a'][$a])) {
|
||||
list($r, $sub_v) = $this->xURI($n['a'][$a], $ct['base'], $ct['ns']);
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
return $this->createBnodeID();
|
||||
}
|
||||
|
||||
function getCurrentObjectLiteral($n, $ct) {
|
||||
$r = array('value' => '', 'lang' => $ct['lang'], 'datatype' => '');
|
||||
if (isset($n['a']['content'])) {
|
||||
$r['value'] = $n['a']['content'];
|
||||
}
|
||||
elseif (isset($n['a']['title'])) {
|
||||
$r['value'] = $n['a']['title'];
|
||||
}
|
||||
else {
|
||||
$r['value'] = $this->getPlainContent($n);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function xURI($v, $base, $ns, $attr_type = '') {
|
||||
if ((list($sub_r, $sub_v) = $this->xQname($v, $base, $ns)) && $sub_r) {
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
if (preg_match('/^(rel|rev|class|name)$/', $attr_type) && preg_match('/^[a-z0-9]+$/', $v)) {
|
||||
return array(0, $v);
|
||||
}
|
||||
return array($this->calcURI($v, $base), '');
|
||||
}
|
||||
|
||||
function xQname($v, $base, $ns) {
|
||||
if ($sub_r = $this->x('([a-z0-9\-\_]+)[\-\.]([a-z0-9\-\_]+)', $v)) {
|
||||
if (isset($ns[$sub_r[1]])) {
|
||||
return array($ns[$sub_r[1]] . $sub_r[2], '');
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
182
arc/extractors/ARC2_MicroformatsExtractor.php
Normal file
182
arc/extractors/ARC2_MicroformatsExtractor.php
Normal file
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 microformats Extractor
|
||||
author: Benjamin Nowack
|
||||
version:
|
||||
*/
|
||||
|
||||
ARC2::inc('ARC2_PoshRdfExtractor');
|
||||
|
||||
class ARC2_MicroformatsExtractor extends ARC2_PoshRdfExtractor {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_MicroformatsExtractor($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->terms = $this->getTerms();
|
||||
$this->ns_prefix = 'mf';
|
||||
$this->a['ns']['mf'] = 'http://poshrdf.org/ns/mf#';
|
||||
$this->caller->detected_formats['posh-rdf'] = 1;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function preProcessNode($n) {
|
||||
if (!$n) return $n;
|
||||
/* remove existing poshRDF hooks */
|
||||
if (!is_array($n['a'])) $n['a'] = array();
|
||||
$n['a']['class'] = isset($n['a']['class']) ? preg_replace('/\s?rdf\-(s|p|o|o-xml)/', '', $n['a']['class']): '';
|
||||
if (!isset($n['a']['rel'])) $n['a']['rel'] = '';
|
||||
/* inject poshRDF hooks */
|
||||
foreach ($this->terms as $term => $infos) {
|
||||
if ((!in_array('rel', $infos) && $this->hasClass($n, $term)) || $this->hasRel($n, $term)) {
|
||||
if ($this->v('scope', '', $infos)) $infos[] = 'p';
|
||||
foreach (array('s', 'p', 'o', 'o-xml') as $type) {
|
||||
if (in_array($type, $infos)) {
|
||||
$n['a']['class'] .= ' rdf-' . $type;
|
||||
$n['a']['class'] = preg_replace('/(^|\s)' . $term . '(\s|$)/s', '\\1mf-' . $term . '\\2', $n['a']['class']);
|
||||
$n['a']['rel'] = preg_replace('/(^|\s)' . $term . '(\s|$)/s', '\\1mf-' . $term . '\\2', $n['a']['rel']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$n['a']['class m'] = split(' ', $n['a']['class']);
|
||||
$n['a']['rel m'] = split(' ', $n['a']['rel']);
|
||||
return $n;
|
||||
}
|
||||
|
||||
function getPredicates($n, $ns) {
|
||||
$ns = array('mf' => $ns['mf']);
|
||||
return parent::getPredicates($n, $ns);
|
||||
}
|
||||
|
||||
function tweakObject($o, $p, $ct) {
|
||||
$ns = $ct['ns']['mf'];
|
||||
/* rel-tag, skill => extract from URL */
|
||||
if (in_array($p, array($ns . 'tag', $ns . 'skill'))) {
|
||||
$o = preg_replace('/^.*\/([^\/]+)/', '\\1', trim($o, '/'));
|
||||
$o = urldecode(rawurldecode($o));
|
||||
}
|
||||
return $o;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTerms() {
|
||||
/* no need to define 'p' if scope is not empty */
|
||||
return array(
|
||||
'acquaintance' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'additional-name' => array('o', 'scope' => array('n')),
|
||||
'adr' => array('s', 'o', 'scope' => array('_doc', 'vcard')),
|
||||
'affiliation' => array('s', 'o', 'scope' => array('hresume')),
|
||||
'author' => array('s', 'o', 'scope' => array('hentry')),
|
||||
'bday' => array('o', 'scope' => array('vcard')),
|
||||
'bio' => array('o', 'scope' => array('vcard')),
|
||||
'best' => array('o', 'scope' => array('hreview')),
|
||||
'bookmark' => array('o', 'scope' => array('_doc', 'hentry', 'hreview')),
|
||||
'class' => array('o', 'scope' => array('vcard', 'vevent')),
|
||||
'category' => array('o', 's', 'scope' => array('vcard', 'vevent')),
|
||||
'child' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'co-resident' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'co-worker' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'colleague' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'contact' => array('o', 'scope' => array('_doc', 'hresume', 'hentry')),
|
||||
'country-name' => array('o', 'scope' => array('adr')),
|
||||
'crush' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'date' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'description' => array('o', 'scope' => array('vevent', 'hreview', 'xfolkentry')),
|
||||
'directory' => array('o', 'rel', 'scope' => array('_doc', 'hfeed', 'hentry', 'hreview')),
|
||||
'dtend' => array('o', 'scope' => array('vevent')),
|
||||
'dtreviewed' => array('o', 'scope' => array('hreview')),
|
||||
'dtstamp' => array('o', 'scope' => array('vevent')),
|
||||
'dtstart' => array('o', 'scope' => array('vevent')),
|
||||
'duration' => array('o', 'scope' => array('vevent')),
|
||||
'education' => array('s', 'o', 'scope' => array('hresume')),
|
||||
'email' => array('s', 'o', 'scope' => array('vcard')),
|
||||
'entry-title' => array('o', 'scope' => array('hentry')),
|
||||
'entry-content' => array('o-xml', 'scope' => array('hentry')),
|
||||
'entry-summary' => array('o', 'scope' => array('hentry')),
|
||||
'experience' => array('s', 'o', 'scope' => array('hresume')),
|
||||
'extended-address' => array('o', 'scope' => array('adr')),
|
||||
'family-name' => array('o', 'scope' => array('n')),
|
||||
'fn' => array('o', 'plain', 'scope' => array('vcard', 'item')),
|
||||
'friend' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'geo' => array('s', 'scope' => array('_doc', 'vcard', 'vevent')),
|
||||
'given-name' => array('o', 'scope' => array('n')),
|
||||
'hentry' => array('s', 'o', 'scope' => array('_doc', 'hfeed')),
|
||||
'hfeed' => array('s', 'scope' => array('_doc')),
|
||||
'honorific-prefix' => array('o', 'scope' => array('n')),
|
||||
'honorific-suffix' => array('o', 'scope' => array('n')),
|
||||
'hresume' => array('s', 'scope' => array('_doc')),
|
||||
'hreview' => array('s', 'scope' => array('_doc')),
|
||||
'item' => array('s', 'scope' => array('hreview')),
|
||||
'key' => array('o', 'scope' => array('vcard')),
|
||||
'kin' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'label' => array('o', 'scope' => array('vcard')),
|
||||
'last-modified' => array('o', 'scope' => array('vevent')),
|
||||
'latitude' => array('o', 'scope' => array('geo')),
|
||||
'license' => array('o', 'rel', 'scope' => array('_doc', 'hfeed', 'hentry', 'hreview')),
|
||||
'locality' => array('o', 'scope' => array('adr')),
|
||||
'location' => array('o', 'scope' => array('vevent')),
|
||||
'logo' => array('o', 'scope' => array('vcard')),
|
||||
'longitude' => array('o', 'scope' => array('geo')),
|
||||
'mailer' => array('o', 'scope' => array('vcard')),
|
||||
'me' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'met' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'muse' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'n' => array('s', 'o', 'scope' => array('vcard')),
|
||||
'neighbor' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'nickname' => array('o', 'plain', 'scope' => array('vcard')),
|
||||
'nofollow' => array('o', 'rel', 'scope' => array('_doc')),
|
||||
'note' => array('o', 'scope' => array('vcard')),
|
||||
'org' => array('o', 'xplain', 'scope' => array('vcard')),
|
||||
'parent' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'permalink' => array('o', 'scope' => array('hreview')),
|
||||
'photo' => array('o', 'scope' => array('vcard', 'item')),
|
||||
'post-office-box' => array('o', 'scope' => array('adr')),
|
||||
'postal-code' => array('o', 'scope' => array('adr')),
|
||||
'publication' => array('s', 'o', 'scope' => array('hresume')),
|
||||
'published' => array('o', 'scope' => array('hentry')),
|
||||
'rating' => array('o', 'scope' => array('hreview')),
|
||||
'region' => array('o', 'scope' => array('adr')),
|
||||
'rev' => array('o', 'scope' => array('vcard')),
|
||||
'reviewer' => array('s', 'o', 'scope' => array('hreview')),
|
||||
'role' => array('o', 'plain', 'scope' => array('vcard')),
|
||||
'sibling' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'skill' => array('o', 'scope' => array('hresume')),
|
||||
'sort-string' => array('o', 'scope' => array('vcard')),
|
||||
'sound' => array('o', 'scope' => array('vcard')),
|
||||
'spouse' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'status' => array('o', 'plain', 'scope' => array('vevent')),
|
||||
'street-address' => array('o', 'scope' => array('adr')),
|
||||
'summary' => array('o', 'scope' => array('vevent', 'hreview', 'hresume')),
|
||||
'sweetheart' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
|
||||
'tag' => array('o', 'rel', 'scope' => array('_doc', 'category', 'hfeed', 'hentry', 'skill', 'hreview', 'xfolkentry')),
|
||||
'taggedlink' => array('o', 'scope' => array('xfolkentry')),
|
||||
'title' => array('o', 'scope' => array('vcard')),
|
||||
'type' => array('o', 'scope' => array('adr', 'email', 'hreview', 'tel')),
|
||||
'tz' => array('o', 'scope' => array('vcard')),
|
||||
'uid' => array('o', 'scope' => array('vcard', 'vevent')),
|
||||
'updated' => array('o', 'scope' => array('hentry')),
|
||||
'url' => array('o', 'scope' => array('vcard', 'vevent', 'item')),
|
||||
'value' => array('o', 'scope' => array('email', 'adr', 'tel')),
|
||||
'vcard' => array('s', 'scope' => array('author', 'reviewer', 'affiliation', 'contact')),
|
||||
'version' => array('o', 'scope' => array('hreview')),
|
||||
'vevent' => array('s', 'scope' => array('_doc')),
|
||||
'worst' => array('o', 'scope' => array('hreview')),
|
||||
'xfolkentry' => array('s', 'scope' => array('_doc')),
|
||||
);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
66
arc/extractors/ARC2_OpenidExtractor.php
Normal file
66
arc/extractors/ARC2_OpenidExtractor.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 foaf:openid Extractor
|
||||
author: Benjamin Nowack
|
||||
version: 2007-10-08
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFExtractor');
|
||||
|
||||
class ARC2_OpenidExtractor extends ARC2_RDFExtractor {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_OpenidExtractor($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->a['ns']['foaf'] = 'http://xmlns.com/foaf/0.1/';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractRDF() {
|
||||
$t_vals = array();
|
||||
$t = '';
|
||||
foreach ($this->nodes as $n) {
|
||||
if (isset($n['tag']) && $n['tag'] == 'link') {
|
||||
$m = 'extract' . ucfirst($n['tag']);
|
||||
list ($t_vals, $t) = $this->$m($n, $t_vals, $t);
|
||||
}
|
||||
}
|
||||
if ($t) {
|
||||
$doc = $this->getFilledTemplate($t, $t_vals, $n['doc_base']);
|
||||
$this->addTs(ARC2::getTriplesFromIndex($doc));
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractLink($n, $t_vals, $t) {
|
||||
if ($this->hasRel($n, 'openid.server')) {
|
||||
if ($href = $this->v('href uri', '', $n['a'])) {
|
||||
$t_vals['doc_owner'] = $this->getDocOwnerID($n);
|
||||
$t_vals['doc_id'] = $this->getDocID($n);
|
||||
$t .= '?doc_owner foaf:homepage ?doc_id ; foaf:openid ?doc_id . ';
|
||||
}
|
||||
}
|
||||
if ($this->hasRel($n, 'openid.delegate')) {
|
||||
if ($href = $this->v('href uri', '', $n['a'])) {
|
||||
$t_vals['doc_owner'] = $this->getDocOwnerID($n);
|
||||
$t .= '?doc_owner foaf:homepage <' . $href . '> ; foaf:openid <' . $href . '> . ';
|
||||
}
|
||||
}
|
||||
return array($t_vals, $t);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
258
arc/extractors/ARC2_PoshRdfExtractor.php
Normal file
258
arc/extractors/ARC2_PoshRdfExtractor.php
Normal file
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 poshRDF Extractor
|
||||
author: Benjamin Nowack
|
||||
version:
|
||||
*/
|
||||
|
||||
ARC2::inc('ARC2_RDFExtractor');
|
||||
|
||||
class ARC2_PoshRdfExtractor extends ARC2_RDFExtractor {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_PoshRdfExtractor($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->terms = $this->v('posh_terms', array(), $this->a);
|
||||
$this->ns_prefix = 'posh';
|
||||
$this->a['ns'] += array(
|
||||
'an' => 'http://www.w3.org/2000/10/annotation-ns#',
|
||||
'content' => 'http://purl.org/rss/1.0/modules/content/',
|
||||
'dc' => 'http://purl.org/dc/elements/1.1/',
|
||||
'dct' => 'http://purl.org/dc/terms/',
|
||||
'foaf' => 'http://xmlns.com/foaf/0.1/',
|
||||
'geo' => 'http://www.w3.org/2003/01/geo/wgs84_pos#',
|
||||
'ical' => 'http://www.w3.org/2002/12/cal/icaltzd#',
|
||||
'owl' => 'http://www.w3.org/2002/07/owl#',
|
||||
'posh' => 'http://poshrdf.org/ns/posh/',
|
||||
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
||||
'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
|
||||
'rev' => 'http://www.purl.org/stuff/rev#',
|
||||
'rss' => 'http://purl.org/rss/1.0/',
|
||||
'sioc' => 'http://rdfs.org/sioc/ns#',
|
||||
'skos' => 'http://www.w3.org/2008/05/skos#',
|
||||
'uri' => 'http://www.w3.org/2006/uri#',
|
||||
'vcard' => 'http://www.w3.org/2006/vcard/ns#',
|
||||
'xfn' => 'http://gmpg.org/xfn/11#',
|
||||
'xml' => 'http://www.w3.org/XML/1998/namespace',
|
||||
'xsd' => 'http://www.w3.org/2001/XMLSchema#',
|
||||
);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractRDF() {
|
||||
if (!isset($this->caller->detected_formats['posh-rdf'])) return 0;
|
||||
$n = $this->getRootNode();
|
||||
$base = $this->getDocBase();
|
||||
$context = array(
|
||||
'id' => $n['id'],
|
||||
'tag' => $n['tag'],
|
||||
'base' => $base,
|
||||
's' => array(array('_doc', $base)),
|
||||
'next_s' => array('_doc', $base),
|
||||
'ps' => array(),
|
||||
'ns' => $this->a['ns'],
|
||||
'lang' => '',
|
||||
'rpointer' => '',
|
||||
);
|
||||
$ct = $this->processNode($n, $context, 0, 1);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getRootNode() {
|
||||
foreach ($this->nodes as $id => $node) {
|
||||
if ($node['tag'] == 'html') {
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
return $this->nodes[0];
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processNode($n, $ct, $level, $pos) {
|
||||
$n = $this->preProcessNode($n);
|
||||
/* local context */
|
||||
$lct = array_merge($ct, array(
|
||||
'ns' => array_merge($ct['ns'], $this->v('xmlns', array(), $n['a'])),
|
||||
'rpointer' => isset($n['a']['id']) ? $n['a']['id'] : ($n['tag'] == 'cdata' ? '' : $ct['rpointer'] . '/' . $pos),
|
||||
'tag' => $n['tag'],
|
||||
'id' => $n['id'],
|
||||
'lang' => $this->v('xml:lang', $ct['lang'], $n['a']),
|
||||
));
|
||||
/* s stack */
|
||||
$next_s_key = $lct['next_s'][0];
|
||||
$next_s_val = $lct['next_s'][1];
|
||||
if ($lct['s'][0][0] != $next_s_key) {
|
||||
$lct['s'] = array_merge(array($lct['next_s']), $lct['s']);
|
||||
}
|
||||
else {
|
||||
$lct['s'][0][1] = $next_s_val;
|
||||
}
|
||||
/* new s */
|
||||
if ($this->hasClass($n, 'rdf-s')) {
|
||||
$lct['next_s'] = array($n['a']['class'], $this->getSubject($n, $lct));
|
||||
//echo "\ns: " . print_r($lct['next_s'], 1);
|
||||
}
|
||||
/* p */
|
||||
if ($this->hasClass($n, 'rdf-p') || $this->hasRel($n, 'rdf-p')) {
|
||||
if ($ps = $this->getPredicates($n, $lct['ns'])) {
|
||||
$lct['ps'] = $ps;
|
||||
$this->addPoshTypes($lct);
|
||||
}
|
||||
}
|
||||
/* o */
|
||||
$cls = $this->v('class', '', $n['a']);
|
||||
if ($lct['ps'] && preg_match('/(^|\s)rdf\-(o|o\-(xml|dateTime|float|integer|boolean))($|\s)/s', $cls, $m)) {
|
||||
$this->addTriples($n, $lct, $m[3]);
|
||||
}
|
||||
/* sub-nodes */
|
||||
if ($sub_nodes = $this->getSubNodes($n)) {
|
||||
$cur_ct = $lct;
|
||||
$sub_pos = 1;
|
||||
foreach ($sub_nodes as $i => $sub_node) {
|
||||
if (in_array($sub_node['tag'], array('cdata', 'comment'))) continue;
|
||||
$sub_ct = $this->processNode($sub_node, $cur_ct, $level + 1, $sub_pos);
|
||||
$sub_pos++;
|
||||
$cur_ct['next_s'] = $sub_ct['next_s'];
|
||||
$cur_ct['ps'] = $sub_ct['ps'];
|
||||
}
|
||||
}
|
||||
return $lct;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getSubject($n, $ct) {
|
||||
foreach (array('href uri', 'src uri', 'title', 'value') as $k) {
|
||||
if (isset($n['a'][$k])) return $n['a'][$k];
|
||||
}
|
||||
/* rpointer */
|
||||
return $ct['base'] . '#resource(' . $ct['rpointer'] . ')';
|
||||
}
|
||||
|
||||
function getPredicates($n, $ns) {
|
||||
$r = array();
|
||||
/* try pnames */
|
||||
$vals = array_merge($this->v('class m', array(), $n['a']), $this->v('rel m', array(), $n['a']));
|
||||
foreach ($vals as $val) {
|
||||
if (!preg_match('/^([a-z0-9]+)\-([a-z0-9\-\_]+)$/i', $val, $m)) continue;
|
||||
if (!isset($ns[$m[1]])) continue;
|
||||
if (preg_match('/^rdf-(s|p|o|o-(xml|dateTime|float|integer|boolean))$/', $val)) continue;
|
||||
$r[] = $ns[$m[1]] . $m[2];
|
||||
}
|
||||
/* try other attributes */
|
||||
if (!$r) {
|
||||
foreach (array('href uri', 'title') as $k) {
|
||||
if (isset($n['a'][$k])) {
|
||||
$r[] = $n['a'][$k];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function addTriples($n, $ct, $o_type) {
|
||||
foreach (array('href uri', 'src uri', 'title', 'value') as $k) {
|
||||
if (isset($n['a'][$k])) {
|
||||
$node_o = $n['a'][$k];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isset($node_o) && $this->hasClass($n, 'rdf-s')) {
|
||||
$node_o = $ct['next_s'][1];
|
||||
}
|
||||
$lit_o = ($o_type == 'xml') ? $this->getContent($n) : $this->getPlainContent($n);
|
||||
$posh_ns = $ct['ns'][$this->ns_prefix];
|
||||
$rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
$xsd = 'http://www.w3.org/2001/XMLSchema#';
|
||||
foreach ($ct['ps'] as $p) {
|
||||
$p_key = str_replace($posh_ns, '', $p);
|
||||
/* dt or obj */
|
||||
$o = $this->isDatatypeProperty($p_key) ? $lit_o : (isset($node_o) ? $node_o : $lit_o);
|
||||
if (!$o) continue;
|
||||
if (!$s = $this->getContainerSubject($ct, $p_key)) continue;
|
||||
$lang = (($o == $lit_o) && !$o_type) ? $ct['lang'] : '';
|
||||
$o = $this->tweakObject($o, $p, $ct);
|
||||
$this->addT(array(
|
||||
's' => $this->getContainerSubject($ct, $p_key),
|
||||
's_type' => preg_match('/^\_\:/', $s) ? 'bnode' : 'uri',
|
||||
'p' => $p,
|
||||
'o' => $o,
|
||||
'o_type' => $this->getObjectType($o, $p_key),
|
||||
'o_lang' => $lang,
|
||||
'o_datatype' => ($o_type == 'xml') ? $rdf . 'XMLLiteral' : ($o_type ? $xsd . $o_type : ''),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
function addPoshTypes($ct) {
|
||||
$posh_ns = $ct['ns'][$this->ns_prefix];
|
||||
foreach ($ct['ps'] as $p) {
|
||||
$p_key = str_replace($posh_ns, '', $p);
|
||||
if (!$this->isSubject($p_key)) continue;
|
||||
$s = $ct['next_s'][1];
|
||||
$this->addT(array(
|
||||
's' => $s,
|
||||
's_type' => preg_match('/^\_\:/', $s) ? 'bnode' : 'uri',
|
||||
'p' => $ct['ns']['rdf'] . 'type',
|
||||
'o' => $posh_ns . ucfirst($p_key),
|
||||
'o_type' => 'uri',
|
||||
'o_lang' => '',
|
||||
'o_datatype' => '',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function preProcessNode($n) {
|
||||
return $n;
|
||||
}
|
||||
|
||||
function getContainerSubject($ct, $term) {
|
||||
if (!isset($this->terms[$term])) return $ct['s'][0][1];
|
||||
$scope = $this->v('scope', array(), $this->terms[$term]);
|
||||
if (!$scope) return $ct['s'][0][1];
|
||||
$scope_re = join('|', $scope);
|
||||
foreach ($ct['s'] as $s) {
|
||||
if (preg_match('/(^|\s)(' . $scope_re. ')($|\s)/s', str_replace($this->ns_prefix . '-', '', $s[0]))) return $s[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function isSubject($term) {
|
||||
if (!isset($this->terms[$term])) return 0;
|
||||
return in_array('s', $this->terms[$term]);
|
||||
}
|
||||
|
||||
function isDatatypeProperty($term) {
|
||||
if (!isset($this->terms[$term])) return 0;
|
||||
return in_array('plain', $this->terms[$term]);
|
||||
}
|
||||
|
||||
function getObjectType($o, $term) {
|
||||
if ($this->isDatatypeProperty($term)) return 'literal';
|
||||
if (strpos($o, ' ')) return 'literal';
|
||||
return preg_match('/^([a-z0-9\_]+)\:[^\s]+$/s', $o, $m) ? ($m[1] == '_' ? 'bnode' : 'uri') : 'literal';
|
||||
}
|
||||
|
||||
function tweakObject($o, $p, $ct) {
|
||||
return $o;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
249
arc/extractors/ARC2_RDFExtractor.php
Normal file
249
arc/extractors/ARC2_RDFExtractor.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 RDF Extractor
|
||||
author: Benjamin Nowack
|
||||
version: 2008-11-18 (Fix: Skip comments. Thanks to Masahide Kanzaki)
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_RDFExtractor extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_RDFExtractor($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->nodes = $this->caller->getNodes();
|
||||
$this->index = $this->caller->getNodeIndex();
|
||||
$this->bnode_prefix = $this->v('bnode_prefix', 'arc' . substr(md5(uniqid(rand())), 0, 4) . 'b', $this->a);
|
||||
$this->bnode_id = 0;
|
||||
$this->keep_cdata_ws = $this->v('keep_cdata_whitespace', 0, $this->a);
|
||||
if (!isset($this->a['ns'])) $this->a['ns'] = array('rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function x($re, $v, $options = 'si') {
|
||||
return ARC2::x($re, $v, $options);
|
||||
}
|
||||
|
||||
function camelCase($v) {
|
||||
$r = ucfirst($v);
|
||||
while (preg_match('/^(.*)[\-\_ ](.*)$/', $r, $m)) {
|
||||
$r = $m[1] . ucfirst($m[2]);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function createBnodeID(){
|
||||
$this->bnode_id++;
|
||||
return '_:' . $this->bnode_prefix . $this->bnode_id;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractRDF() {
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function addTs($ts) {
|
||||
foreach ($ts as $t) {
|
||||
$this->caller->addT($t);
|
||||
}
|
||||
}
|
||||
|
||||
function addT($t) {
|
||||
return $this->caller->addT($t);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getSubNodes($n) {
|
||||
return $this->v($n['id'], array(), $this->index);
|
||||
}
|
||||
|
||||
function getParentNode($n) {
|
||||
return isset($this->nodes[$n['p_id']]) ? $this->nodes[$n['p_id']] : 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getSubNodesByClass($n, $cls, $skip_self = 0) {
|
||||
if (!$skip_self && $this->hasClass($n, $cls)) {
|
||||
return array($n);
|
||||
}
|
||||
$r = array();
|
||||
$sns = $this->getSubNodes($n);
|
||||
foreach ($sns as $sn) {
|
||||
if ($sub_r = $this->getSubNodesByClass($sn, $cls, 0)) {
|
||||
$r = array_merge($r, $sub_r);
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getSubNodeByClass($n, $cls, $skip_self = 0) {
|
||||
if (!$skip_self && $this->hasClass($n, $cls)) {
|
||||
return $n;
|
||||
}
|
||||
$sns = $this->getSubNodes($n);
|
||||
foreach ($sns as $sn) {
|
||||
if ($sub_r = $this->getSubNodeByClass($sn, $cls, 0)) {
|
||||
return $sub_r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getParentNodeByClass($n, $cls, $skip_self = 0) {
|
||||
if (!$skip_self && $this->hasClass($n, $cls)) {
|
||||
return $n;
|
||||
}
|
||||
if ($pn = $this->getParentNode($n)) {
|
||||
if ($sub_r = $this->getParentNodeByClass($pn, $cls, 0)) {
|
||||
return $sub_r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function hasAttribute($a, $n, $v) {
|
||||
$vs = is_array($v) ? $v : array($v);
|
||||
$a_vs = $this->v($a . ' m', array(), $n['a']);
|
||||
return array_intersect($vs, $a_vs) ? 1 : 0;
|
||||
}
|
||||
|
||||
function hasClass($n, $v) {
|
||||
return $this->hasAttribute('class', $n, $v);
|
||||
}
|
||||
|
||||
function hasRel($n, $v) {
|
||||
return $this->hasAttribute('rel', $n, $v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getDocBase() {
|
||||
$root_node = $this->getRootNode();
|
||||
$r = $root_node['doc_base'];
|
||||
foreach ($this->getSubNodes($root_node) as $root_child) {
|
||||
if ($root_child['tag'] == 'head') {
|
||||
foreach ($this->getSubNodes($root_child) as $head_child) {
|
||||
if ($head_child['tag'] == 'base') {
|
||||
$r = $head_child['a']['href'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getPlainContent($n, $trim = 1, $use_img_alt = 1) {
|
||||
if ($n['tag'] == 'comment') {
|
||||
$r = '';
|
||||
}
|
||||
elseif ($n['tag'] == 'cdata') {
|
||||
$r = $n['a']['value'];
|
||||
}
|
||||
elseif (trim($this->v('cdata', '', $n))) {
|
||||
$r = $n['cdata'];
|
||||
$sub_nodes = $this->getSubNodes($n);
|
||||
foreach ($sub_nodes as $sub_n) {
|
||||
$r .= $this->getPlainContent($sub_n, 0, $use_img_alt);
|
||||
}
|
||||
}
|
||||
elseif (($n['tag'] == 'img') && $use_img_alt && isset($n['a']['alt'])) {
|
||||
$r = $n['a']['alt'];
|
||||
}
|
||||
else {
|
||||
$r = '';
|
||||
$sub_nodes = $this->getSubNodes($n);
|
||||
foreach ($sub_nodes as $sub_n) {
|
||||
$r .= $this->getPlainContent($sub_n, 0, $use_img_alt);
|
||||
}
|
||||
}
|
||||
$r = preg_replace('/\s/s', ' ', $r);
|
||||
$r = preg_replace('/\s\s*/s', ' ', $r);
|
||||
return $trim ? trim($r) : $r;
|
||||
}
|
||||
|
||||
function getContent($n, $outer = 0, $trim = 1) {
|
||||
//echo '<pre>' . htmlspecialchars(print_r($n, 1)) . '</pre>';
|
||||
if ($n['tag'] == 'comment') {
|
||||
$r = '<!-- ' . $n['a']['value'] . ' -->';
|
||||
}
|
||||
elseif ($n['tag'] == 'cdata') {
|
||||
$r = $n['a']['value'];
|
||||
}
|
||||
else {
|
||||
$r = '';
|
||||
if ($outer) {
|
||||
$r .= '<' . $n['tag'];
|
||||
asort($n['a']);
|
||||
if (isset($n['a']['xmlns']) && $n['a']['xmlns']['']) {
|
||||
$r .= ' xmlns="' . $n['a']['xmlns'][''] . '"';
|
||||
}
|
||||
foreach ($n['a'] as $a => $val) {
|
||||
if (!is_array($val) && isset($n['a'][$a . ' uri'])) $val = $n['a'][$a . ' uri'];
|
||||
$r .= preg_match('/^[^\s]+$/', $a) && !is_array($val) ? ' ' . $a . '="' . addslashes($val) . '"' : '';
|
||||
}
|
||||
$r .= $n['empty'] ? '/>' : '>';
|
||||
}
|
||||
if (!$n['empty']) {
|
||||
$r .= $this->v('cdata', '', $n);
|
||||
$sub_nodes = $this->getSubNodes($n);
|
||||
foreach ($sub_nodes as $sub_n) {
|
||||
$r .= $this->getContent($sub_n, 1, 0);
|
||||
}
|
||||
if ($outer) {
|
||||
$r .= '</' . $n['tag'] . '>';
|
||||
}
|
||||
}
|
||||
}
|
||||
return ($trim && !$this->keep_cdata_ws) ? trim($r) : $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getDocID($n) {
|
||||
$id = $n['id'];
|
||||
$k = 'doc_' . $id;
|
||||
if (!isset($this->caller->cache[$k])) {
|
||||
$this->caller->cache[$k] = $n['doc_url'];
|
||||
}
|
||||
return $this->caller->cache[$k];
|
||||
}
|
||||
|
||||
function getDocOwnerID($n) {
|
||||
return '_:owner_of_' . $this->normalize($this->getDocID($n));
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function normalize($v) {
|
||||
$v = preg_replace('/[\W\s]+/is', '_', strip_tags(strtolower($v)));
|
||||
$v = preg_replace('/http/', '', $v);
|
||||
$v = preg_replace('/[\_]+/', '_', $v);
|
||||
//$v = substr($v, 0, 30);
|
||||
$v = trim($v, '_');
|
||||
return $v;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
389
arc/extractors/ARC2_RdfaExtractor.php
Normal file
389
arc/extractors/ARC2_RdfaExtractor.php
Normal file
@@ -0,0 +1,389 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 RDFa Extractor
|
||||
author: Benjamin Nowack
|
||||
version: 2009-05-29 (Fix: CURIEs support DOTs now)
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFExtractor');
|
||||
|
||||
class ARC2_RdfaExtractor extends ARC2_RDFExtractor {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_RdfaExtractor($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractRDF() {
|
||||
//echo '<pre>' . htmlspecialchars(print_r($this->nodes, 1)) . '</pre>';
|
||||
if (!isset($this->caller->detected_formats['rdfa'])) return 0;
|
||||
$root_node = $this->getRootNode();
|
||||
//$base = $this->v('xml:base', $this->getDocBase(), $root_node['a']);
|
||||
$base = $this->getDocBase();
|
||||
$context = array(
|
||||
'base' => $base,
|
||||
'p_s' => $base,
|
||||
'p_o' => '',
|
||||
'ns' => array(),
|
||||
'inco_ts' => array(),
|
||||
'lang' => '',
|
||||
);
|
||||
$this->processNode($root_node, $context, 0);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getRootNode() {
|
||||
foreach ($this->nodes as $id => $node) {
|
||||
if ($node['tag'] == 'html') {
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
return $this->nodes[0];
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processNode($n, $ct, $level) {
|
||||
if ($n['tag']=='cdata' || $n['tag']=='comment') return null; /* patch by tobyink */
|
||||
$ts_added = 0;
|
||||
/* step 1 */
|
||||
$lct = array();
|
||||
$lct['prev_s'] = $this->v('prev_s', $this->v('p_s', '', $ct), $ct);
|
||||
$lct['recurse'] = 1;
|
||||
$lct['skip'] = 0;
|
||||
$lct['new_s'] = '';
|
||||
$lct['cur_o_res'] = '';
|
||||
$lct['inco_ts'] = array();
|
||||
$lct['base'] = $ct['base'];
|
||||
//$lct['base'] = $this->v('xml:base', $ct['base'], $n['a']);
|
||||
/* step 2 */
|
||||
$lct['ns'] = array_merge($ct['ns'], $this->v('xmlns', array(), $n['a']));
|
||||
/* step 3 */
|
||||
$lct['lang'] = $this->v('xml:lang', $ct['lang'], $n['a']);
|
||||
/* step 4 */
|
||||
$rel_uris = $this->getAttributeURIs($n, $ct, $lct, 'rel');
|
||||
$rev_uris = $this->getAttributeURIs($n, $ct, $lct, 'rev');
|
||||
if (!$rel_uris && !$rev_uris) {
|
||||
foreach (array('about', 'src', 'resource', 'href') as $attr) {
|
||||
if (isset($n['a'][$attr]) && (list($uri, $sub_v) = $this->xURI($n['a'][$attr], $lct['base'], $lct['ns'], '', $lct)) && $uri) {
|
||||
$lct['new_s'] = $uri;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$lct['new_s']) {
|
||||
if (preg_match('/(head|body)/i', $n['tag'])) {
|
||||
$lct['new_s'] = $lct['base'];
|
||||
}
|
||||
elseif ($this->getAttributeURIs($n, $ct, $lct, 'typeof')) {
|
||||
$lct['new_s'] = $this->createBnodeID();
|
||||
}
|
||||
elseif ($ct['p_o']) {
|
||||
$lct['new_s'] = $ct['p_o'];
|
||||
//$lct['skip'] = 1;
|
||||
if(!isset($n['a']['property'])) $lct['skip'] = 1;/* patch by masaka */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* step 5 */
|
||||
else {
|
||||
foreach (array('about', 'src') as $attr) {
|
||||
if (isset($n['a'][$attr]) && (list($uri, $sub_v) = $this->xURI($n['a'][$attr], $lct['base'], $lct['ns'], '', $lct)) && $uri) {
|
||||
$lct['new_s'] = $uri;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$lct['new_s']) {
|
||||
if (preg_match('/(head|body)/i', $n['tag'])) {
|
||||
$lct['new_s'] = $lct['base'];
|
||||
}
|
||||
elseif ($this->getAttributeURIs($n, $ct, $lct, 'typeof')) {
|
||||
$lct['new_s'] = $this->createBnodeID();
|
||||
}
|
||||
elseif ($ct['p_o']) {
|
||||
$lct['new_s'] = $ct['p_o'];
|
||||
}
|
||||
}
|
||||
foreach (array('resource', 'href') as $attr) {
|
||||
if (isset($n['a'][$attr]) && (list($uri, $sub_v) = $this->xURI($n['a'][$attr], $lct['base'], $lct['ns'], '', $lct)) && $uri) {
|
||||
$lct['cur_o_res'] = $uri;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* step 6 */
|
||||
if ($lct['new_s']) {
|
||||
if ($uris = $this->getAttributeURIs($n, $ct, $lct, 'typeof')) {
|
||||
foreach ($uris as $uri) {
|
||||
$this->addT(array(
|
||||
's' => $lct['new_s'],
|
||||
's_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
|
||||
'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
|
||||
'o' => $uri,
|
||||
'o_type' => 'uri',
|
||||
'o_lang' => '',
|
||||
'o_datatype' => '',
|
||||
));
|
||||
$ts_added = 1;
|
||||
}
|
||||
}
|
||||
/* step 7 */
|
||||
if ($lct['cur_o_res']) {
|
||||
if ($rel_uris) {
|
||||
foreach ($rel_uris as $uri) {
|
||||
$this->addT(array(
|
||||
's' => $lct['new_s'],
|
||||
's_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
|
||||
'p' => $uri,
|
||||
'o' => $lct['cur_o_res'],
|
||||
'o_type' => preg_match('/^\_\:/', $lct['cur_o_res']) ? 'bnode' : 'uri',
|
||||
'o_lang' => '',
|
||||
'o_datatype' => '',
|
||||
));
|
||||
$ts_added = 1;
|
||||
}
|
||||
}
|
||||
if ($rev_uris) {
|
||||
foreach ($rev_uris as $uri) {
|
||||
$this->addT(array(
|
||||
's' => $lct['cur_o_res'],
|
||||
's_type' => preg_match('/^\_\:/', $lct['cur_o_res']) ? 'bnode' : 'uri',
|
||||
'p' => $uri,
|
||||
'o' => $lct['new_s'],
|
||||
'o_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
|
||||
'o_lang' => '',
|
||||
'o_datatype' => '',
|
||||
));
|
||||
$ts_added = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* step 8 */
|
||||
if (!$lct['cur_o_res']) {
|
||||
if ($rel_uris || $rev_uris) {
|
||||
$lct['cur_o_res'] = $this->createBnodeID();
|
||||
foreach ($rel_uris as $uri) {
|
||||
$lct['inco_ts'][] = array('p' => $uri, 'dir' => 'fwd');
|
||||
}
|
||||
foreach ($rev_uris as $uri) {
|
||||
$lct['inco_ts'][] = array('p' => $uri, 'dir' => 'rev');
|
||||
}
|
||||
}
|
||||
}
|
||||
/* step 10 */
|
||||
if (!$lct['skip'] && ($new_s = $lct['new_s'])) {
|
||||
//if ($new_s = $lct['new_s']) {
|
||||
if ($uris = $this->getAttributeURIs($n, $ct, $lct, 'property')) {
|
||||
foreach ($uris as $uri) {
|
||||
$lct['cur_o_lit'] = $this->getCurrentObjectLiteral($n, $lct, $ct);
|
||||
$this->addT(array(
|
||||
's' => $lct['new_s'],
|
||||
's_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
|
||||
'p' => $uri,
|
||||
'o' => $lct['cur_o_lit']['value'],
|
||||
'o_type' => 'literal',
|
||||
'o_lang' => $lct['cur_o_lit']['lang'],
|
||||
'o_datatype' => $lct['cur_o_lit']['datatype'],
|
||||
));
|
||||
$ts_added = 1;
|
||||
if ($lct['cur_o_lit']['datatype'] == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral') {
|
||||
$lct['recurse'] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* step 11 (10) */
|
||||
$complete_triples = 0;
|
||||
if ($lct['recurse']) {
|
||||
if ($lct['skip']) {
|
||||
$new_ct = array_merge($ct, array('base' => $lct['base'], 'lang' => $lct['lang'], 'ns' => $lct['ns']));
|
||||
}
|
||||
else {
|
||||
$new_ct = array(
|
||||
'base' => $lct['base'],
|
||||
'p_s' => $lct['new_s'] ? $lct['new_s'] : $ct['p_s'],
|
||||
'p_o' => $lct['cur_o_res'] ? $lct['cur_o_res'] : ($lct['new_s'] ? $lct['new_s'] : $ct['p_s']),
|
||||
'ns' => $lct['ns'],
|
||||
'inco_ts' => $lct['inco_ts'],
|
||||
'lang' => $lct['lang']
|
||||
);
|
||||
}
|
||||
$sub_nodes = $this->getSubNodes($n);
|
||||
foreach ($sub_nodes as $sub_node) {
|
||||
if ($this->processNode($sub_node, $new_ct, $level+1)) {
|
||||
$complete_triples = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* step 12 (11) */
|
||||
$other = 0;
|
||||
if ($ts_added || $complete_triples || ($lct['new_s'] && !preg_match('/^\_\:/', $lct['new_s'])) || ($other == 1)) {
|
||||
//if (!$lct['skip'] && ($complete_triples || ($lct['new_s'] && !preg_match('/^\_\:/', $lct['new_s'])))) {
|
||||
foreach ($ct['inco_ts'] as $inco_t) {
|
||||
if ($inco_t['dir'] == 'fwd') {
|
||||
$this->addT(array(
|
||||
's' => $ct['p_s'],
|
||||
's_type' => preg_match('/^\_\:/', $ct['p_s']) ? 'bnode' : 'uri',
|
||||
'p' => $inco_t['p'],
|
||||
'o' => $lct['new_s'],
|
||||
'o_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
|
||||
'o_lang' => '',
|
||||
'o_datatype' => '',
|
||||
));
|
||||
}
|
||||
elseif ($inco_t['dir'] == 'rev') {
|
||||
$this->addT(array(
|
||||
's' => $lct['new_s'],
|
||||
's_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
|
||||
'p' => $inco_t['p'],
|
||||
'o' => $ct['p_s'],
|
||||
'o_type' => preg_match('/^\_\:/', $ct['p_s']) ? 'bnode' : 'uri',
|
||||
'o_lang' => '',
|
||||
'o_datatype' => '',
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* step 13 (12) (result flag) */
|
||||
if ($ts_added) return 1;
|
||||
if ($lct['new_s'] && !preg_match('/^\_\:/', $lct['new_s'])) return 1;
|
||||
if ($complete_triples) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getAttributeURIs($n, $ct, $lct, $attr) {
|
||||
$vals = ($val = $this->v($attr, '', $n['a'])) ? explode(' ', $val) : array();
|
||||
$r = array();
|
||||
foreach ($vals as $val) {
|
||||
if(!trim($val)) continue;
|
||||
if ((list($uri, $sub_v) = $this->xURI(trim($val), $lct['base'], $lct['ns'], $attr, $lct)) && $uri) {
|
||||
$r[] = $uri;
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getCurrentObjectLiteral($n, $lct, $ct) {
|
||||
$xml_val = $this->getContent($n);
|
||||
$plain_val = $this->getPlainContent($n, 0, 0);
|
||||
if (function_exists('html_entity_decode')) {
|
||||
$plain_val = html_entity_decode($plain_val, ENT_QUOTES);
|
||||
}
|
||||
$dt = $this->v('datatype', '', $n['a']);
|
||||
list($dt_uri, $sub_v) = $this->xURI($dt, $lct['base'], $lct['ns'], '', $lct);
|
||||
$dt = $dt ? $dt_uri : $dt;
|
||||
$r = array('value' => '', 'lang' => $lct['lang'], 'datatype' => $dt);
|
||||
if (isset($n['a']['content'])) {
|
||||
$r['value'] = $n['a']['content'];
|
||||
if (function_exists('html_entity_decode')) {
|
||||
$r['value'] = html_entity_decode($r['value'], ENT_QUOTES);
|
||||
}
|
||||
}
|
||||
elseif ($xml_val == $plain_val) {
|
||||
$r['value'] = $plain_val;
|
||||
}
|
||||
elseif (!preg_match('/[\<\>]/', $xml_val)) {
|
||||
$r['value'] = $xml_val;
|
||||
}
|
||||
elseif (isset($n['a']['datatype']) && ($dt != 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral')) {
|
||||
$r['value'] = $plain_val;
|
||||
}
|
||||
elseif (!isset($n['a']['datatype']) || ($dt == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral')) {
|
||||
$r['value'] = $this->injectXMLDeclarations($xml_val, $lct['ns'], $lct['lang']);
|
||||
$r['datatype'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral';
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function injectXMLDeclarations($val, $ns, $lang) {//@@todo proper node rebuilding */
|
||||
$lang_code = $lang ? ' xml:lang="' . $lang . '"' : '';
|
||||
/* ns */
|
||||
$val = preg_replace('/<([a-z0-9]+)([\>\s])/is', '<\\1 xmlns="http://www.w3.org/1999/xhtml"' . $lang_code . '\\2', $val);
|
||||
foreach ($ns as $prefix => $uri) {
|
||||
if ($prefix && ($pos = strpos(' ' . $val, '<' . $prefix . ':'))) {
|
||||
$val = substr($val, 0, $pos - 1) . preg_replace('/^(<' . $prefix . '\:[^\>\s]+)/', '\\1 xmlns:' . $prefix. '="' . $uri . '"' . $lang_code, substr($val, $pos - 1));
|
||||
}
|
||||
}
|
||||
/* remove accidentally added xml:lang and xmlns= */
|
||||
$val = preg_replace('/(\<[^\>]*)( xml\:lang[^\s\>]+)([^\>]*)(xml\:lang[^\s\>]+)/s', '\\1\\3\\4', $val);
|
||||
$val = preg_replace('/(\<[^\>]*)( xmlns=[^\s\>]+)([^\>]*)(xmlns=[^\s\>]+)/s', '\\1\\3\\4', $val);
|
||||
return $val;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function xURI($v, $base, $ns, $attr_type = '', $lct = '') {
|
||||
if ((list($sub_r, $sub_v) = $this->xBlankCURIE($v, $base, $ns)) && $sub_r) {
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xSafeCURIE($v, $base, $ns, $lct)) && $sub_r) {
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xCURIE($v, $base, $ns)) && $sub_r) {
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
if (preg_match('/^(rel|rev)$/', $attr_type) && preg_match('/^\s*(alternate|appendix|bookmark|cite|chapter|contents|copyright|glossary|help|icon|index|last|license|meta|next|p3pv1|prev|role|section|stylesheet|subsection|start|up)(\s|$)/is', $v, $m)) {
|
||||
return array('http://www.w3.org/1999/xhtml/vocab#' . strtolower($m[1]), preg_replace('/^\s*' . $m[1]. '/is', '', $v));
|
||||
}
|
||||
if (preg_match('/^(rel|rev)$/', $attr_type) && preg_match('/^[a-z0-9\.]+$/i', $v)) {
|
||||
return array(0, $v);
|
||||
}
|
||||
return array($this->calcURI($v, $base), '');
|
||||
}
|
||||
|
||||
function xBlankCURIE($v, $base, $ns) {
|
||||
if ($sub_r = $this->x('\[\_\:\]', $v)) {
|
||||
$this->empty_bnode = isset($this->empty_bnode) ? $this->empty_bnode : $this->createBnodeID();
|
||||
return array($this->empty_bnode, '');
|
||||
}
|
||||
if ($sub_r = $this->x('\[?(\_\:[a-z0-9\_\-]+)\]?', $v)) {
|
||||
return array($sub_r[1], '');
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
function xSafeCURIE($v, $base, $ns, $lct = '') {
|
||||
/* empty */
|
||||
if ($sub_r = $this->x('\[\]', $v)) {
|
||||
$r = $lct ? $lct['prev_s'] : $base;/* should be current subject value */
|
||||
return $sub_r[1] ? array($r, $sub_r[1]) : array($r, '');
|
||||
}
|
||||
if ($sub_r = $this->x('\[([^\:]*)\:([^\]]*)\]', $v)) {
|
||||
if (!$sub_r[1]) return array('http://www.w3.org/1999/xhtml/vocab#' . $sub_r[2], '');
|
||||
if (isset($ns[$sub_r[1]])) {
|
||||
return array($ns[$sub_r[1]] . $sub_r[2], '');
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
function xCURIE($v, $base, $ns) {
|
||||
if ($sub_r = $this->x('([a-z0-9\-\_]*)\:([^\s]+)', $v)) {
|
||||
if (!$sub_r[1]) return array('http://www.w3.org/1999/xhtml/vocab#' . $sub_r[2], '');
|
||||
if (isset($ns[$sub_r[1]])) {
|
||||
return array($ns[$sub_r[1]] . $sub_r[2], '');
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
49
arc/extractors/ARC2_TwitterProfilePicExtractor.php
Normal file
49
arc/extractors/ARC2_TwitterProfilePicExtractor.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Extractor
|
||||
author: Benjamin Nowack
|
||||
version: 2008-12-09
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFExtractor');
|
||||
|
||||
class ARC2_TwitterProfilePicExtractor extends ARC2_RDFExtractor {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_TwitterProfilePicExtractor($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->a['ns']['foaf'] = 'http://xmlns.com/foaf/0.1/';
|
||||
$this->a['ns']['mf'] = 'http://poshrdf.org/ns/mf#';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractRDF() {
|
||||
$t_vals = array();
|
||||
$t = '';
|
||||
foreach ($this->nodes as $n) {
|
||||
if (isset($n['tag']) && ($n['tag'] == 'img') && ($this->v('id', '', $n['a']) == 'profile-image')) {
|
||||
$t_vals['vcard_id'] = $this->getDocID($n) . '#resource(side/1/2/1)';
|
||||
$t .= '?vcard_id mf:photo <' . $n['a']['src'] . '> . ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($t) {
|
||||
$doc = $this->getFilledTemplate($t, $t_vals, $n['doc_base']);
|
||||
$this->addTs(ARC2::getTriplesFromIndex($doc));
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
249
arc/parsers/ARC2_AtomParser.php
Normal file
249
arc/parsers/ARC2_AtomParser.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Atom Parser
|
||||
author: Benjamin Nowack
|
||||
version: 2009-04-21 (Addition: support for link types)
|
||||
*/
|
||||
|
||||
ARC2::inc('LegacyXMLParser');
|
||||
|
||||
class ARC2_AtomParser extends ARC2_LegacyXMLParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_AtomParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* reader */
|
||||
parent::__init();
|
||||
$this->triples = array();
|
||||
$this->target_encoding = '';
|
||||
$this->t_count = 0;
|
||||
$this->added_triples = array();
|
||||
$this->skip_dupes = false;
|
||||
$this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
|
||||
$this->bnode_id = 0;
|
||||
$this->cache = array();
|
||||
$this->allowCDataNodes = 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function done() {
|
||||
$this->extractRDF();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function setReader(&$reader) {
|
||||
$this->reader =& $reader;
|
||||
}
|
||||
|
||||
function createBnodeID(){
|
||||
$this->bnode_id++;
|
||||
return '_:' . $this->bnode_prefix . $this->bnode_id;
|
||||
}
|
||||
|
||||
function addT($t) {
|
||||
//if (!isset($t['o_datatype']))
|
||||
if ($this->skip_dupes) {
|
||||
//$h = md5(print_r($t, 1));
|
||||
$h = md5(serialize($t));
|
||||
if (!isset($this->added_triples[$h])) {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
$this->added_triples[$h] = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
}
|
||||
}
|
||||
|
||||
function getTriples() {
|
||||
return $this->v('triples', array());
|
||||
}
|
||||
|
||||
function countTriples() {
|
||||
return $this->t_count;
|
||||
}
|
||||
|
||||
function getSimpleIndex($flatten_objects = 1, $vals = '') {
|
||||
return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractRDF() {
|
||||
$index = $this->getNodeIndex();
|
||||
//print_r($index);
|
||||
$this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
$this->atom = 'http://www.w3.org/2005/Atom';
|
||||
$this->rss = 'http://purl.org/rss/1.0/';
|
||||
$this->dc = 'http://purl.org/dc/elements/1.1/';
|
||||
$this->sioc = 'http://rdfs.org/sioc/ns#';
|
||||
$this->dct = 'http://purl.org/dc/terms/';
|
||||
$this->content = 'http://purl.org/rss/1.0/modules/content/';
|
||||
$this->enc = 'http://purl.oclc.org/net/rss_2.0/enc#';
|
||||
$this->mappings = array(
|
||||
'feed' => $this->rss . 'channel',
|
||||
'entry' => $this->rss . 'item',
|
||||
'title' => $this->rss . 'title',
|
||||
'link' => $this->rss . 'link',
|
||||
'summary' => $this->rss . 'description',
|
||||
'content' => $this->content . 'encoded',
|
||||
'id' => $this->dc . 'identifier',
|
||||
'author' => $this->dc . 'creator',
|
||||
'category' => $this->dc . 'subject',
|
||||
'updated' => $this->dc . 'date',
|
||||
'source' => $this->dc . 'source',
|
||||
);
|
||||
$this->dt_props = array(
|
||||
$this->dc . 'identifier',
|
||||
$this->rss . 'link'
|
||||
);
|
||||
foreach ($index as $p_id => $nodes) {
|
||||
foreach ($nodes as $pos => $node) {
|
||||
$tag = $this->v('tag', '', $node);
|
||||
if ($tag == 'feed') {
|
||||
$struct = $this->extractChannel($index[$node['id']]);
|
||||
$triples = ARC2::getTriplesFromIndex($struct);
|
||||
foreach ($triples as $t) {
|
||||
$this->addT($t);
|
||||
}
|
||||
}
|
||||
elseif ($tag == 'entry') {
|
||||
$struct = $this->extractItem($index[$node['id']]);
|
||||
$triples = ARC2::getTriplesFromIndex($struct);
|
||||
foreach ($triples as $t) {
|
||||
$this->addT($t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function extractChannel($els) {
|
||||
list($props, $sub_index) = $this->extractProps($els, 'channel');
|
||||
$uri = $props[$this->rss . 'link'][0]['value'];
|
||||
return ARC2::getMergedIndex(array($uri => $props), $sub_index);
|
||||
}
|
||||
|
||||
function extractItem($els) {
|
||||
list($props, $sub_index) = $this->extractProps($els, 'item');
|
||||
$uri = $props[$this->rss . 'link'][0]['value'];
|
||||
return ARC2::getMergedIndex(array($uri => $props), $sub_index);
|
||||
}
|
||||
|
||||
function extractProps($els, $container) {
|
||||
$r = array($this->rdf . 'type' => array(array('value' => $this->rss . $container, 'type' => 'uri')));
|
||||
$sub_index = array();
|
||||
foreach ($els as $info) {
|
||||
/* key */
|
||||
$tag = $info['tag'];
|
||||
if (!preg_match('/^[a-z0-9]+\:/i', $tag)) {
|
||||
$k = isset($this->mappings[$tag]) ? $this->mappings[$tag] : '';
|
||||
}
|
||||
elseif (isset($this->mappings[$tag])) {
|
||||
$k = $this->mappings[$tag];
|
||||
}
|
||||
else {/* qname */
|
||||
$k = $this->expandPName($tag);
|
||||
}
|
||||
//echo $k . "\n";
|
||||
if (($container == 'channel') && ($k == $this->rss . 'item')) continue;
|
||||
/* val */
|
||||
$v = trim($info['cdata']);
|
||||
if (!$v) $v = $this->v('href uri', '', $info['a']);
|
||||
/* prop */
|
||||
if ($k) {
|
||||
/* content handling */
|
||||
if (in_array($k, array($this->rss . 'description', $this->content . 'encoded'))) {
|
||||
$v = $this->getNodeContent($info);
|
||||
}
|
||||
/* source handling */
|
||||
elseif ($k == $this->dc . 'source') {
|
||||
$sub_nodes = $this->node_index[$info['id']];
|
||||
foreach ($sub_nodes as $sub_pos => $sub_info) {
|
||||
if ($sub_info['tag'] == 'id') {
|
||||
$v = trim($sub_info['cdata']);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* link handling */
|
||||
elseif ($k == $this->rss . 'link') {
|
||||
if ($link_type = $this->v('type', '', $info['a'])) {
|
||||
$k2 = $this->dc . 'format';
|
||||
if (!isset($sub_index[$v])) $sub_index[$v] = array();
|
||||
if (!isset($sub_index[$v][$k2])) $sub_index[$v][$k2] = array();
|
||||
$sub_index[$v][$k2][] = array('value' => $link_type, 'type' => 'literal');
|
||||
}
|
||||
}
|
||||
/* author handling */
|
||||
elseif ($k == $this->dc . 'creator') {
|
||||
$sub_nodes = $this->node_index[$info['id']];
|
||||
foreach ($sub_nodes as $sub_pos => $sub_info) {
|
||||
if ($sub_info['tag'] == 'name') {
|
||||
$v = trim($sub_info['cdata']);
|
||||
}
|
||||
if ($sub_info['tag'] == 'uri') {
|
||||
$k2 = $this->sioc . 'has_creator';
|
||||
$v2 = trim($sub_info['cdata']);
|
||||
if (!isset($r[$k2])) $r[$k2] = array();
|
||||
$r[$k2][] = array('value' => $v2, 'type' => 'uri');
|
||||
}
|
||||
}
|
||||
}
|
||||
/* date handling */
|
||||
elseif (in_array($k, array($this->dc . 'date', $this->dct . 'modified'))) {
|
||||
if (!preg_match('/^[0-9]{4}/', $v) && ($sub_v = strtotime($v)) && ($sub_v != -1)) {
|
||||
$tz = date('Z', $sub_v); /* timezone offset */
|
||||
$sub_v -= $tz; /* utc */
|
||||
$v = date('Y-m-d\TH:i:s\Z', $sub_v);
|
||||
}
|
||||
}
|
||||
/* tag handling */
|
||||
elseif ($k == $this->dc . 'subject') {
|
||||
$v = $this->v('term', '', $info['a']);
|
||||
}
|
||||
/* other attributes in closed tags */
|
||||
elseif (!$v && ($info['state'] == 'closed') && $info['a']) {
|
||||
foreach ($info['a'] as $sub_k => $sub_v) {
|
||||
if (!preg_match('/(xmlns|\:|type)/', $sub_k)) {
|
||||
$v = $sub_v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isset($r[$k])) $r[$k] = array();
|
||||
$r[$k][] = array('value' => $v, 'type' => in_array($k, $this->dt_props) || !preg_match('/^[a-z0-9]+\:[^\s]+$/is', $v) ? 'literal' : 'uri');
|
||||
}
|
||||
}
|
||||
return array($r, $sub_index);
|
||||
}
|
||||
|
||||
function initXMLParser() {
|
||||
if (!isset($this->xml_parser)) {
|
||||
$enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
|
||||
$parser = xml_parser_create($enc);
|
||||
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
|
||||
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
|
||||
xml_set_element_handler($parser, 'open', 'close');
|
||||
xml_set_character_data_handler($parser, 'cData');
|
||||
xml_set_start_namespace_decl_handler($parser, 'nsDecl');
|
||||
xml_set_object($parser, $this);
|
||||
$this->xml_parser =& $parser;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
|
||||
}
|
||||
202
arc/parsers/ARC2_CBJSONParser.php
Normal file
202
arc/parsers/ARC2_CBJSONParser.php
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 CrunchBase API JSON Parser
|
||||
author: Benjamin Nowack
|
||||
version: 2008-08-06 (Tweak: Removed inferred "full_permalink", there is a native "crunchbase_url" now)
|
||||
*/
|
||||
|
||||
ARC2::inc('JSONParser');
|
||||
|
||||
class ARC2_CBJSONParser extends ARC2_JSONParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_CBJSONParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* reader */
|
||||
parent::__init();
|
||||
$this->base = 'http://cb.semsol.org/';
|
||||
$this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
$this->default_ns = $this->base . 'ns#';
|
||||
$this->nsp = array($this->rdf => 'rdf');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function done() {
|
||||
$this->extractRDF();
|
||||
}
|
||||
|
||||
function extractRDF() {
|
||||
$struct = $this->struct;
|
||||
if ($type = $this->getStructType($struct)) {
|
||||
$s = $this->getResourceID($struct, $type);
|
||||
/* rdf:type */
|
||||
$this->addT($s, $this->rdf . 'type', $this->default_ns . $this->camelCase($type), 'uri', 'uri');
|
||||
/* explicit triples */
|
||||
$this->extractResourceRDF($struct, $s);
|
||||
}
|
||||
//print_r($struct);
|
||||
}
|
||||
|
||||
function getStructType($struct, $rel = '') {
|
||||
/* rel-based */
|
||||
if ($rel == 'person') return 'person';
|
||||
if ($rel == 'company') return 'company';
|
||||
if ($rel == 'acquiring_company') return 'company';
|
||||
if ($rel == 'firm') return 'company';
|
||||
if ($rel == 'provider') return 'service-provider';
|
||||
/* struct-based */
|
||||
if (isset($struct['_type'])) return $struct['_type'];
|
||||
if (isset($struct['round_code'])) return 'funding_round';
|
||||
if (isset($struct['products'])) return 'company';
|
||||
if (isset($struct['first_name'])) return 'person';
|
||||
if (isset($struct['investments'])) return 'financial-organization';
|
||||
if (isset($struct['launched_year'])) return 'product';
|
||||
if (isset($struct['providerships']) && is_array($struct['providerships'])) return 'service-provider';
|
||||
return '';
|
||||
}
|
||||
|
||||
function getResourceID($struct, $type) {
|
||||
if ($type && isset($struct['permalink'])) return $this->base . $type . '/' . $struct['permalink'] . '#self';
|
||||
return $this->createBnodeID();
|
||||
}
|
||||
|
||||
function getPropertyURI($name, $ns = '') {
|
||||
if (!$ns) $ns = $this->default_ns;
|
||||
if (preg_match('/^(product|funding_round|investment|acquisition|.+ship|office|milestone|.+embed|.+link)s/', $name, $m)) $name = $m[1];
|
||||
if ($name == 'tag_list') $name = 'tag';
|
||||
if ($name == 'competitions') $name = 'competitor';
|
||||
return $ns . $name;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractResourceRDF($struct, $s) {
|
||||
$s_type = preg_match('/^\_\:/', $s) ? 'bnode' : 'uri';
|
||||
foreach ($struct as $k => $v) {
|
||||
if ($k == 'acquisition') $k = 'exit';
|
||||
$sub_m = 'extract' . $this->camelCase($k) . 'RDF';
|
||||
if (method_exists($this, $sub_m)) {
|
||||
$this->$sub_m($s, $s_type, $v);
|
||||
continue;
|
||||
}
|
||||
$p = $this->getPropertyURI($k);
|
||||
if (!$v) continue;
|
||||
/* simple, single v */
|
||||
if (!is_array($v)) {
|
||||
$o_type = preg_match('/^[a-z]+\:[^\s]+$/is', $v) ? 'uri' : 'literal';
|
||||
$this->addT($s, $p, trim($v), $s_type, $o_type);
|
||||
}
|
||||
/* structured, single v */
|
||||
elseif (!$this->isFlatArray($v)) {
|
||||
if ($o_type = $this->getStructType($v, $k)) {/* known type */
|
||||
$o = $this->getResourceID($v, $o_type);
|
||||
$this->addT($s, $p, $o, $s_type, 'uri');
|
||||
$this->addT($o, $this->rdf . 'type', $this->default_ns . $this->camelCase($o_type), 'uri', 'uri');
|
||||
}
|
||||
else {/* unknown type */
|
||||
$o = $this->createBnodeID();
|
||||
$this->addT($s, $p, $o, $s_type, 'bnode');
|
||||
$this->extractResourceRDF($v, $o);
|
||||
}
|
||||
}
|
||||
/* value list */
|
||||
else {
|
||||
foreach ($v as $sub_v) {
|
||||
$this->extractResourceRDF(array($k => $sub_v), $s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isFlatArray($v) {
|
||||
foreach ($v as $k => $sub_v) {
|
||||
return is_numeric($k) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractTagListRDF($s, $s_type, $v) {
|
||||
$tags = split(', ', $v);
|
||||
foreach ($tags as $tag) {
|
||||
if (!trim($tag)) continue;
|
||||
$this->addT($s, $this->getPropertyURI('tag'), $tag, $s_type, 'literal');
|
||||
}
|
||||
}
|
||||
|
||||
function extractImageRDF($s, $s_type, $v) {
|
||||
if (!$v) return 1;
|
||||
$sizes = $v['available_sizes'];
|
||||
foreach ($sizes as $size) {
|
||||
$w = $size[0][0];
|
||||
$h = $size[0][1];
|
||||
$img = 'http://www.crunchbase.com/' . $size[1];
|
||||
$this->addT($s, $this->getPropertyURI('image'), $img, $s_type, 'uri');
|
||||
$this->addT($img, $this->getPropertyURI('width'), $w, 'uri', 'literal');
|
||||
$this->addT($img, $this->getPropertyURI('height'), $h, 'uri', 'literal');
|
||||
}
|
||||
}
|
||||
|
||||
function extractProductsRDF($s, $s_type, $v) {
|
||||
foreach ($v as $sub_v) {
|
||||
$o = $this->getResourceID($sub_v, 'product');
|
||||
$this->addT($s, $this->getPropertyURI('product'), $o, $s_type, 'uri');
|
||||
}
|
||||
}
|
||||
|
||||
function extractCompetitionsRDF($s, $s_type, $v) {
|
||||
foreach ($v as $sub_v) {
|
||||
$o = $this->getResourceID($sub_v['competitor'], 'company');
|
||||
$this->addT($s, $this->getPropertyURI('competitor'), $o, $s_type, 'uri');
|
||||
}
|
||||
}
|
||||
|
||||
function extractFundingRoundsRDF($s, $s_type, $v) {
|
||||
foreach ($v as $sub_v) {
|
||||
$o = $this->createBnodeID();
|
||||
$this->addT($s, $this->getPropertyURI('funding_round'), $o, $s_type, 'bnode');
|
||||
$this->extractResourceRDF($sub_v, $o);
|
||||
}
|
||||
}
|
||||
|
||||
function extractInvestmentsRDF($s, $s_type, $v) {
|
||||
foreach ($v as $sub_v) {
|
||||
/* incoming */
|
||||
foreach (array('person' => 'person', 'company' => 'company', 'financial_org' => 'financial-organization') as $k => $type) {
|
||||
if (isset($sub_v[$k])) $this->addT($s, $this->getPropertyURI('investment'), $this->getResourceID($sub_v[$k], $type), $s_type, 'uri');
|
||||
}
|
||||
/* outgoing */
|
||||
if (isset($sub_v['funding_round'])) {
|
||||
$o = $this->createBnodeID();
|
||||
$this->addT($s, $this->getPropertyURI('investment'), $o, $s_type, 'bnode');
|
||||
$this->extractResourceRDF($sub_v['funding_round'], $o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function extractExternalLinksRDF($s, $s_type, $v) {
|
||||
foreach ($v as $sub_v) {
|
||||
$this->addT($s, $this->getPropertyURI('external_link'), $sub_v['external_url'], $s_type, 'uri');
|
||||
$this->addT($sub_v['external_url'], $this->getPropertyURI('title'), $sub_v['title'], $s_type, 'literal');
|
||||
}
|
||||
}
|
||||
|
||||
function extractWebPresencesRDF($s, $s_type, $v) {
|
||||
foreach ($v as $sub_v) {
|
||||
$this->addT($s, $this->getPropertyURI('web_presence'), $sub_v['external_url'], $s_type, 'uri');
|
||||
$this->addT($sub_v['external_url'], $this->getPropertyURI('title'), $sub_v['title'], $s_type, 'literal');
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
151
arc/parsers/ARC2_JSONParser.php
Normal file
151
arc/parsers/ARC2_JSONParser.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 JSON Parser
|
||||
author: Benjamin Nowack
|
||||
version: 2009-02-12 Tweak: "null" is now supported by extractValue
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFParser');
|
||||
|
||||
class ARC2_JSONParser extends ARC2_RDFParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_JSONParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function x($re, $v, $options = 'si') {
|
||||
while (preg_match('/^\s*(\/\*.*\*\/)(.*)$/Usi', $v, $m)) {/* comment removal */
|
||||
$v = $m[2];
|
||||
}
|
||||
$this->unparsed_code = (strlen($this->unparsed_code) > strlen($v)) ? $v : $this->unparsed_code;
|
||||
return ARC2::x($re, $v, $options);
|
||||
}
|
||||
|
||||
function parse($path, $data = '') {
|
||||
$this->state = 0;
|
||||
/* reader */
|
||||
if (!$this->v('reader')) {
|
||||
ARC2::inc('Reader');
|
||||
$this->reader = & new ARC2_Reader($this->a, $this);
|
||||
}
|
||||
$this->reader->setAcceptHeader('Accept: application/json; q=0.9, */*; q=0.1');
|
||||
$this->reader->activate($path, $data);
|
||||
$this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
|
||||
/* parse */
|
||||
$doc = '';
|
||||
while ($d = $this->reader->readStream()) {
|
||||
$doc .= $d;
|
||||
}
|
||||
$this->reader->closeStream();
|
||||
unset($this->reader);
|
||||
$doc = preg_replace('/^[^\{]*(.*\})[^\}]*$/is', '\\1', $doc);
|
||||
$this->unparsed_code = $doc;
|
||||
list($this->struct, $rest) = $this->extractObject($doc);
|
||||
return $this->done();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractObject($v) {
|
||||
if (function_exists('json_decode')) return array(json_decode($v, 1), '');
|
||||
$r = array();
|
||||
if ($sub_r = $this->x('\{', $v)) {
|
||||
$v = $sub_r[1];
|
||||
while ((list($sub_r, $v) = $this->extractEntry($v)) && $sub_r) {
|
||||
$r[$sub_r['key']] = $sub_r['value'];
|
||||
}
|
||||
if ($sub_r = $this->x('\}', $v)) $v = $sub_r[1];
|
||||
}
|
||||
elseif ($sub_r = $this->x('\[', $v)) {
|
||||
$v = $sub_r[1];
|
||||
while ((list($sub_r, $v) = $this->extractValue($v)) && $sub_r) {
|
||||
$r[] = $sub_r;
|
||||
}
|
||||
if ($sub_r = $this->x('\]', $v)) $v = $sub_r[1];
|
||||
}
|
||||
elseif ((list($sub_r, $v) = $this->extractValue($v)) && $sub_r) {
|
||||
$r = $sub_r;
|
||||
}
|
||||
return array($r, $v);
|
||||
}
|
||||
|
||||
function extractEntry($v) {
|
||||
if ($r = $this->x('\,', $v)) $v = $r[1];
|
||||
/* k */
|
||||
if ($r = $this->x('\"([^\"]+)\"\s*\:', $v)) {
|
||||
$k = $r[1];
|
||||
$sub_v = $r[2];
|
||||
if (list($sub_r, $sub_v) = $this->extractObject($sub_v)) {
|
||||
return array(
|
||||
array('key' => $k, 'value' => $sub_r),
|
||||
$sub_v
|
||||
);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
function extractValue($v) {
|
||||
if ($r = $this->x('\,', $v)) $v = $r[1];
|
||||
if ($sub_r = $this->x('null', $v)) {
|
||||
return array(null, $sub_r[1]);
|
||||
}
|
||||
if ($sub_r = $this->x('([0-9\.]+)', $v)) {
|
||||
return array($sub_r[1], $sub_r[2]);
|
||||
}
|
||||
if ($sub_r = $this->x('\"', $v)) {
|
||||
$rest = $sub_r[1];
|
||||
if (preg_match('/^([^\x5c]*|.*[^\x5c]|.*\x5c{2})\"(.*)$/sU', $rest, $m)) {
|
||||
return array($m[1], $m[2]);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getObject() {
|
||||
return $this->v('struct', array());
|
||||
}
|
||||
|
||||
function getTriples() {
|
||||
return $this->v('triples', array());
|
||||
}
|
||||
|
||||
function countTriples() {
|
||||
return $this->t_count;
|
||||
}
|
||||
|
||||
function addT($s = '', $p = '', $o = '', $s_type = '', $o_type = '', $o_dt = '', $o_lang = '') {
|
||||
//echo str_replace($this->base, '', "-----\n adding $s / $p / $o\n-----\n");
|
||||
$t = array('s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang);
|
||||
if ($this->skip_dupes) {
|
||||
$h = md5(serialize($t));
|
||||
if (!isset($this->added_triples[$h])) {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
$this->added_triples[$h] = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
315
arc/parsers/ARC2_LegacyXMLParser.php
Normal file
315
arc/parsers/ARC2_LegacyXMLParser.php
Normal file
@@ -0,0 +1,315 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Legaxy XML Parser
|
||||
author: Benjamin Nowack
|
||||
version: 2008-10-04 (Fix: nsDecl led to warnings when uri was an array.)
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_LegacyXMLParser extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_LegacyXMLParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* reader */
|
||||
parent::__init();
|
||||
$this->encoding = $this->v('encoding', false, $this->a);
|
||||
$this->state = 0;
|
||||
$this->x_base = $this->base;
|
||||
$this->xml = 'http://www.w3.org/XML/1998/namespace';
|
||||
$this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
$this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf');
|
||||
$this->allowCDataNodes = 1;
|
||||
$this->target_encoding = '';
|
||||
$this->keep_cdata_ws = $this->v('keep_cdata_whitespace', 0, $this->a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function setReader(&$reader) {
|
||||
$this->reader =& $reader;
|
||||
}
|
||||
|
||||
function parse($path, $data = '', $iso_fallback = false) {
|
||||
$this->nodes = array();
|
||||
$this->node_count = 0;
|
||||
$this->level = 0;
|
||||
/* reader */
|
||||
if (!$this->v('reader')) {
|
||||
ARC2::inc('Reader');
|
||||
$this->reader = & new ARC2_Reader($this->a, $this);
|
||||
}
|
||||
$this->reader->setAcceptHeader('Accept: application/xml; q=0.9, */*; q=0.1');
|
||||
$this->reader->activate($path, $data);
|
||||
$this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
|
||||
$this->base = $this->x_base;
|
||||
$this->doc_url = $this->reader->base;
|
||||
/* xml parser */
|
||||
$this->initXMLParser();
|
||||
/* parse */
|
||||
$first = true;
|
||||
while ($d = $this->reader->readStream(1)) {
|
||||
if ($iso_fallback && $first) {
|
||||
$d = '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" . preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
|
||||
}
|
||||
if (!xml_parse($this->xml_parser, $d, false)) {
|
||||
$error_str = xml_error_string(xml_get_error_code($this->xml_parser));
|
||||
$line = xml_get_current_line_number($this->xml_parser);
|
||||
if (!$iso_fallback && preg_match("/Invalid character/i", $error_str)) {
|
||||
xml_parser_free($this->xml_parser);
|
||||
unset($this->xml_parser);
|
||||
$this->reader->closeStream();
|
||||
unset($this->reader);
|
||||
$this->__init();
|
||||
$this->encoding = 'ISO-8859-1';
|
||||
$this->initXMLParser();
|
||||
return $this->parse($path, $data, true);
|
||||
}
|
||||
else {
|
||||
return $this->addError('XML error: "' . $error_str . '" at line ' . $line . ' (parsing as ' . $this->getEncoding() . ')');
|
||||
}
|
||||
}
|
||||
$first = false;
|
||||
}
|
||||
$this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
|
||||
xml_parser_free($this->xml_parser);
|
||||
$this->reader->closeStream();
|
||||
unset($this->reader);
|
||||
return $this->done();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getEncoding($src = 'config') {
|
||||
if ($src == 'parser') {
|
||||
return $this->target_encoding;
|
||||
}
|
||||
elseif (($src == 'config') && $this->encoding) {
|
||||
return $this->encoding;
|
||||
}
|
||||
return $this->reader->getEncoding();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function done() {
|
||||
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getStructure() {
|
||||
return array('nodes' => $this->v('nodes', array()));
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getNodeIndex(){
|
||||
if (!isset($this->node_index)) {
|
||||
/* index by parent */
|
||||
$index = array();
|
||||
for ($i = 0, $i_max = count($this->nodes); $i < $i_max; $i++) {
|
||||
$node = $this->nodes[$i];
|
||||
$node['id'] = $i;
|
||||
$node['doc_base'] = $this->base;
|
||||
if (isset($this->doc_url)) $node['doc_url'] = $this->doc_url;
|
||||
$this->updateNode($node);
|
||||
$p_id = $node['p_id'];
|
||||
if (!isset($index[$p_id])) {
|
||||
$index[$p_id] = array();
|
||||
}
|
||||
$index[$p_id][$node['pos']] = $node;
|
||||
}
|
||||
$this->node_index = $index;
|
||||
}
|
||||
return $this->node_index;
|
||||
}
|
||||
|
||||
function getNodes() {
|
||||
return $this->nodes;
|
||||
}
|
||||
|
||||
function getSubNodes($n) {
|
||||
return $this->v($n['id'], array(), $this->getNodeIndex());
|
||||
}
|
||||
|
||||
function getNodeContent($n, $outer = 0, $trim = 1) {
|
||||
//echo '<pre>' . htmlspecialchars(print_r($n, 1)) . '</pre>';
|
||||
if ($n['tag'] == 'cdata') {
|
||||
$r = $n['a']['value'];
|
||||
}
|
||||
else {
|
||||
$r = '';
|
||||
if ($outer) {
|
||||
$r .= '<' . $n['tag'];
|
||||
asort($n['a']);
|
||||
if (isset($n['a']['xmlns']) && $n['a']['xmlns']['']) {
|
||||
$r .= ' xmlns="' . $n['a']['xmlns'][''] . '"';
|
||||
}
|
||||
foreach ($n['a'] as $a => $val) {
|
||||
$r .= preg_match('/^[^\s]+$/', $a) && !is_array($val) ? ' ' . $a . '="' . addslashes($val) . '"' : '';
|
||||
}
|
||||
$r .= $n['empty'] ? '/>' : '>';
|
||||
}
|
||||
if (!$n['empty']) {
|
||||
$r .= $this->v('cdata', '', $n);
|
||||
$sub_nodes = $this->getSubNodes($n);
|
||||
foreach ($sub_nodes as $sub_n) {
|
||||
$r .= $this->getNodeContent($sub_n, 1, 0);
|
||||
}
|
||||
if ($outer) {
|
||||
$r .= '</' . $n['tag'] . '>';
|
||||
}
|
||||
}
|
||||
}
|
||||
return ($trim && !$this->keep_cdata_ws) ? trim($r) : $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function pushNode($n) {
|
||||
$n['id'] = $this->node_count;
|
||||
$this->nodes[$this->node_count] = $n;
|
||||
$this->node_count++;
|
||||
}
|
||||
|
||||
function getCurNode($t = '') {
|
||||
$i = 1;
|
||||
do {
|
||||
$r = $this->node_count ? $this->nodes[$this->node_count - $i] : 0;
|
||||
$found = (!$t || ($r['tag'] == $t)) ? 1 : 0;
|
||||
$i++;
|
||||
} while (!$found && isset($this->nodes[$this->node_count - $i]));
|
||||
return $r;
|
||||
}
|
||||
|
||||
function updateNode($node) {/* php4-save */
|
||||
$this->nodes[$node['id']] = $node;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function initXMLParser() {
|
||||
if (!isset($this->xml_parser)) {
|
||||
$enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
|
||||
$parser = xml_parser_create_ns($enc, '');
|
||||
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
|
||||
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
|
||||
xml_set_element_handler($parser, 'open', 'close');
|
||||
xml_set_character_data_handler($parser, 'cData');
|
||||
xml_set_start_namespace_decl_handler($parser, 'nsDecl');
|
||||
xml_set_object($parser, $this);
|
||||
$this->xml_parser =& $parser;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function open($p, $t, $a) {
|
||||
$t_exact = $t;
|
||||
//echo "<br />\n".'opening '.$t . ' ' . print_r($a, 1); flush();
|
||||
//echo "<br />\n".'opening '.$t; flush();
|
||||
$t = strpos($t, ':') ? $t : strtolower($t);
|
||||
/* base check */
|
||||
$base = '';
|
||||
if (($t == 'base') && isset($a['href'])) {
|
||||
$this->base = $a['href'];
|
||||
$base = $a['href'];
|
||||
}
|
||||
/* URIs */
|
||||
foreach (array('href', 'src', 'id') as $uri_a) {
|
||||
if (isset($a[$uri_a])) {
|
||||
$a[$uri_a . ' uri'] = ($uri_a == 'id') ? $this->calcURI('#'.$a[$uri_a]) : $this->calcURI($a[$uri_a]);
|
||||
}
|
||||
}
|
||||
/* ns */
|
||||
if ($a) {
|
||||
foreach ($a as $k => $v) {
|
||||
if (strpos($k, 'xmlns') === 0) {
|
||||
$this->nsDecl($p, trim(substr($k, 5), ':'), $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* node */
|
||||
$node = array(
|
||||
'tag' => $t,
|
||||
'tag_exact' => $t_exact,
|
||||
'a' => $a,
|
||||
'level' => $this->level,
|
||||
'pos' => 0,
|
||||
'p_id' => $this->node_count-1,
|
||||
'state' => 'open',
|
||||
'empty' => 0,
|
||||
'cdata' =>''
|
||||
);
|
||||
if ($base) {
|
||||
$node['base'] = $base;
|
||||
}
|
||||
/* parent/sibling */
|
||||
if ($this->node_count) {
|
||||
$l = $this->level;
|
||||
$prev_node = $this->getCurNode();
|
||||
if ($prev_node['level'] == $l) {
|
||||
$node['p_id'] = $prev_node['p_id'];
|
||||
$node['pos'] = $prev_node['pos']+1;
|
||||
}
|
||||
elseif($prev_node['level'] > $l) {
|
||||
while($prev_node['level'] > $l) {
|
||||
if (!isset($this->nodes[$prev_node['p_id']])) {
|
||||
//$this->addError('nesting mismatch: tag is ' . $t . ', level is ' . $l . ', prev_level is ' . $prev_node['level'] . ', prev_node p_id is ' . $prev_node['p_id']);
|
||||
break;
|
||||
}
|
||||
$prev_node = $this->nodes[$prev_node['p_id']];
|
||||
}
|
||||
$node['p_id'] = $prev_node['p_id'];
|
||||
$node['pos'] = $prev_node['pos']+1;
|
||||
}
|
||||
}
|
||||
$this->pushNode($node);
|
||||
$this->level++;
|
||||
/* cdata */
|
||||
$this->cur_cdata="";
|
||||
}
|
||||
|
||||
function close($p, $t, $empty = 0) {
|
||||
//echo "<br />\n".'closing '.$t; flush();
|
||||
$node = $this->getCurNode($t);
|
||||
$node['state'] = 'closed';
|
||||
$node['empty'] = $empty;
|
||||
$this->updateNode($node);
|
||||
$this->level--;
|
||||
}
|
||||
|
||||
function cData($p, $d) {
|
||||
//echo trim($d) ? "<br />\n".'cdata: ' . $d : ''; flush();
|
||||
$node = $this->getCurNode();
|
||||
if($node['state'] == 'open') {
|
||||
$node['cdata'] .= $d;
|
||||
$this->updateNode($node);
|
||||
}
|
||||
else {/* cdata is sibling of node */
|
||||
if ($this->allowCDataNodes) {
|
||||
$this->open($p, 'cdata', array('value' => $d));
|
||||
$this->close($p, 'cdata');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function nsDecl($p, $prf, $uri) {
|
||||
if (is_array($uri)) return 1;
|
||||
$this->ns[$prf] = $uri;
|
||||
$this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
131
arc/parsers/ARC2_RDFParser.php
Normal file
131
arc/parsers/ARC2_RDFParser.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 RDF Parser (generic)
|
||||
*
|
||||
* @author Benjamin Nowack <bnowack@semsol.com>
|
||||
* @license http://arc.semsol.org/license
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-12-03
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_RDFParser extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_RDFParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* proxy_host, proxy_port, proxy_skip, http_accept_header, http_user_agent_header, max_redirects, reader, skip_dupes */
|
||||
parent::__init();
|
||||
$this->a['format'] = $this->v('format', false, $this->a);
|
||||
$this->keep_time_limit = $this->v('keep_time_limit', 0, $this->a);
|
||||
$this->triples = array();
|
||||
$this->t_count = 0;
|
||||
$this->added_triples = array();
|
||||
$this->skip_dupes = $this->v('skip_dupes', false, $this->a);
|
||||
$this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
|
||||
$this->bnode_id = 0;
|
||||
$this->format = '';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function setReader(&$reader) {
|
||||
$this->reader =& $reader;
|
||||
}
|
||||
|
||||
function parse($path, $data = '') {
|
||||
/* reader */
|
||||
if (!isset($this->reader)) {
|
||||
ARC2::inc('Reader');
|
||||
$this->reader = & new ARC2_Reader($this->a, $this);
|
||||
}
|
||||
$this->reader->activate($path, $data) ;
|
||||
/* format detection */
|
||||
$mappings = array(
|
||||
'rdfxml' => 'RDFXML',
|
||||
'turtle' => 'Turtle',
|
||||
'sparqlxml' => 'SPOG',
|
||||
'ntriples' => 'Turtle',
|
||||
'html' => 'SemHTML',
|
||||
'rss' => 'RSS',
|
||||
'atom' => 'Atom',
|
||||
'sgajson' => 'SGAJSON',
|
||||
'cbjson' => 'CBJSON'
|
||||
);
|
||||
$format = $this->reader->getFormat();
|
||||
if (!$format || !isset($mappings[$format])) {
|
||||
return $this->addError('No parser available for "' . $format . '".');
|
||||
}
|
||||
$this->format = $format;
|
||||
/* format parser */
|
||||
$suffix = $mappings[$format] . 'Parser';
|
||||
ARC2::inc($suffix);
|
||||
$cls = 'ARC2_' . $suffix;
|
||||
$this->parser =& new $cls($this->a, $this);
|
||||
$this->parser->setReader($this->reader);
|
||||
return $this->parser->parse($path, $data);
|
||||
}
|
||||
|
||||
function parseData($data) {
|
||||
return $this->parse(ARC2::getScriptURI(), $data);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function done() {
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function createBnodeID(){
|
||||
$this->bnode_id++;
|
||||
return '_:' . $this->bnode_prefix . $this->bnode_id;
|
||||
}
|
||||
|
||||
function getTriples() {
|
||||
return $this->v('parser') ? $this->m('getTriples', false, array(), $this->v('parser')) : array();
|
||||
}
|
||||
|
||||
function countTriples() {
|
||||
return $this->v('parser') ? $this->m('countTriples', false, 0, $this->v('parser')) : 0;
|
||||
}
|
||||
|
||||
function getSimpleIndex($flatten_objects = 1, $vals = '') {
|
||||
return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
$this->__init();
|
||||
if (isset($this->reader)) unset($this->reader);
|
||||
if (isset($this->parser)) {
|
||||
$this->parser->__init();
|
||||
unset($this->parser);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractRDF($formats = '') {
|
||||
if (method_exists($this->parser, 'extractRDF')) {
|
||||
return $this->parser->extractRDF($formats);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getEncoding($src = 'config') {
|
||||
if (method_exists($this->parser, 'getEncoding')) {
|
||||
return $this->parser->getEncoding($src);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
643
arc/parsers/ARC2_RDFXMLParser.php
Normal file
643
arc/parsers/ARC2_RDFXMLParser.php
Normal file
@@ -0,0 +1,643 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 RDF/XML Parser
|
||||
*
|
||||
* @author Benjamin Nowack <bnowack@semsol.com>
|
||||
* @license http://arc.semsol.org/license
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-12-03
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFParser');
|
||||
|
||||
class ARC2_RDFXMLParser extends ARC2_RDFParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_RDFXMLParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* reader */
|
||||
parent::__init();
|
||||
$this->encoding = $this->v('encoding', false, $this->a);
|
||||
$this->state = 0;
|
||||
$this->x_lang = '';
|
||||
$this->x_base = $this->base;
|
||||
$this->xml = 'http://www.w3.org/XML/1998/namespace';
|
||||
$this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
$this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf');
|
||||
$this->s_stack = array();
|
||||
$this->s_count = 0;
|
||||
$this->target_encoding = '';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function parse($path, $data = '', $iso_fallback = false) {
|
||||
/* reader */
|
||||
if (!$this->v('reader')) {
|
||||
ARC2::inc('Reader');
|
||||
$this->reader = & new ARC2_Reader($this->a, $this);
|
||||
}
|
||||
$this->reader->setAcceptHeader('Accept: application/rdf+xml; q=0.9, */*; q=0.1');
|
||||
$this->reader->activate($path, $data);
|
||||
$this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
|
||||
/* xml parser */
|
||||
$this->initXMLParser();
|
||||
/* parse */
|
||||
$first = true;
|
||||
while ($d = $this->reader->readStream()) {
|
||||
if (!$this->keep_time_limit) @set_time_limit($this->v('time_limit', 60, $this->a));
|
||||
if ($iso_fallback && $first) {
|
||||
$d = '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" . preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
|
||||
$first = false;
|
||||
}
|
||||
if (!xml_parse($this->xml_parser, $d, false)) {
|
||||
$error_str = xml_error_string(xml_get_error_code($this->xml_parser));
|
||||
$line = xml_get_current_line_number($this->xml_parser);
|
||||
$this->tmp_error = 'XML error: "' . $error_str . '" at line ' . $line . ' (parsing as ' . $this->getEncoding() . ')';
|
||||
if (!$iso_fallback && preg_match("/Invalid character/i", $error_str)) {
|
||||
xml_parser_free($this->xml_parser);
|
||||
unset($this->xml_parser);
|
||||
$this->reader->closeStream();
|
||||
$this->__init();
|
||||
$this->encoding = 'ISO-8859-1';
|
||||
unset($this->xml_parser);
|
||||
unset($this->reader);
|
||||
return $this->parse($path, $data, true);
|
||||
}
|
||||
else {
|
||||
return $this->addError($this->tmp_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
|
||||
xml_parser_free($this->xml_parser);
|
||||
$this->reader->closeStream();
|
||||
unset($this->reader);
|
||||
return $this->done();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function initXMLParser() {
|
||||
if (!isset($this->xml_parser)) {
|
||||
$enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
|
||||
$parser = xml_parser_create_ns($enc, '');
|
||||
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
|
||||
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
|
||||
xml_set_element_handler($parser, 'open', 'close');
|
||||
xml_set_character_data_handler($parser, 'cdata');
|
||||
xml_set_start_namespace_decl_handler($parser, 'nsDecl');
|
||||
xml_set_object($parser, $this);
|
||||
$this->xml_parser =& $parser;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getEncoding($src = 'config') {
|
||||
if ($src == 'parser') {
|
||||
return $this->target_encoding;
|
||||
}
|
||||
elseif (($src == 'config') && $this->encoding) {
|
||||
return $this->encoding;
|
||||
}
|
||||
return $this->reader->getEncoding();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTriples() {
|
||||
return $this->v('triples', array());
|
||||
}
|
||||
|
||||
function countTriples() {
|
||||
return $this->t_count;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function pushS(&$s) {
|
||||
$s['pos'] = $this->s_count;
|
||||
$this->s_stack[$this->s_count] = $s;
|
||||
$this->s_count++;
|
||||
}
|
||||
|
||||
function popS(){/* php 4.0.x-safe */
|
||||
$r = array();
|
||||
$this->s_count--;
|
||||
for ($i = 0, $i_max = $this->s_count; $i < $i_max; $i++) {
|
||||
$r[$i] = $this->s_stack[$i];
|
||||
}
|
||||
$this->s_stack = $r;
|
||||
}
|
||||
|
||||
function updateS($s) {
|
||||
$this->s_stack[$s['pos']] = $s;
|
||||
}
|
||||
|
||||
function getParentS() {
|
||||
return ($this->s_count && isset($this->s_stack[$this->s_count - 1])) ? $this->s_stack[$this->s_count - 1] : false;
|
||||
}
|
||||
|
||||
function getParentXBase() {
|
||||
if ($p = $this->getParentS()) {
|
||||
return isset($p['p_x_base']) && $p['p_x_base'] ? $p['p_x_base'] : (isset($p['x_base']) ? $p['x_base'] : '');
|
||||
}
|
||||
return $this->x_base;
|
||||
}
|
||||
|
||||
function getParentXLang() {
|
||||
if ($p = $this->getParentS()) {
|
||||
return isset($p['p_x_lang']) && $p['p_x_lang'] ? $p['p_x_lang'] : (isset($p['x_lang']) ? $p['x_lang'] : '');
|
||||
}
|
||||
return $this->x_lang;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
|
||||
//echo "-----\nadding $s / $p / $o\n-----\n";
|
||||
$t = array('s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang);
|
||||
if ($this->skip_dupes) {
|
||||
$h = md5(serialize($t));
|
||||
if (!isset($this->added_triples[$h])) {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
$this->added_triples[$h] = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
}
|
||||
}
|
||||
|
||||
function reify($t, $s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
|
||||
$this->addT($t, $this->rdf.'type', $this->rdf.'Statement', 'uri', 'uri');
|
||||
$this->addT($t, $this->rdf.'subject', $s, 'uri', $s_type);
|
||||
$this->addT($t, $this->rdf.'predicate', $p, 'uri', 'uri');
|
||||
$this->addT($t, $this->rdf.'object', $o, 'uri', $o_type, $o_dt, $o_lang);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function open($p, $t, $a) {
|
||||
//echo "state is $this->state\n";
|
||||
//echo "opening $t\n";
|
||||
switch($this->state) {
|
||||
case 0: return $this->h0Open($t, $a);
|
||||
case 1: return $this->h1Open($t, $a);
|
||||
case 2: return $this->h2Open($t, $a);
|
||||
case 4: return $this->h4Open($t, $a);
|
||||
case 5: return $this->h5Open($t, $a);
|
||||
case 6: return $this->h6Open($t, $a);
|
||||
default: $this->addError('open() called at state ' . $this->state . ' in '.$t);
|
||||
}
|
||||
}
|
||||
|
||||
function close($p, $t) {
|
||||
//echo "state is $this->state\n";
|
||||
//echo "closing $t\n";
|
||||
switch($this->state){
|
||||
case 1: return $this->h1Close($t);
|
||||
case 2: return $this->h2Close($t);
|
||||
case 3: return $this->h3Close($t);
|
||||
case 4: return $this->h4Close($t);
|
||||
case 5: return $this->h5Close($t);
|
||||
case 6: return $this->h6Close($t);
|
||||
default: $this->addError('close() called at state ' . $this->state . ' in '.$t);
|
||||
}
|
||||
}
|
||||
|
||||
function cdata($p, $d) {
|
||||
//echo "state is $this->state\n";
|
||||
//echo "cdata\n";
|
||||
switch($this->state){
|
||||
case 4: return $this->h4Cdata($d);
|
||||
case 6: return $this->h6Cdata($d);
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
function nsDecl($p, $prf, $uri) {
|
||||
$this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h0Open($t, $a) {
|
||||
$this->x_lang = $this->v($this->xml.'lang', $this->x_lang, $a);
|
||||
$this->x_base = $this->calcURI($this->v($this->xml.'base', $this->x_base, $a));
|
||||
$this->state = 1;
|
||||
if ($t !== $this->rdf.'RDF') {
|
||||
$this->h1Open($t, $a);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h1Open($t, $a) {
|
||||
$s = array(
|
||||
'x_base' => isset($a[$this->xml.'base']) ? $this->calcURI($a[$this->xml.'base']) : $this->getParentXBase(),
|
||||
'x_lang' => isset($a[$this->xml.'lang']) ? $a[$this->xml.'lang'] : $this->getParentXLang(),
|
||||
'li_count' => 0,
|
||||
);
|
||||
/* ID */
|
||||
if (isset($a[$this->rdf.'ID'])) {
|
||||
$s['type'] = 'uri';
|
||||
$s['value'] = $this->calcURI('#'.$a[$this->rdf.'ID'], $s['x_base']);
|
||||
}
|
||||
/* about */
|
||||
elseif (isset($a[$this->rdf.'about'])) {
|
||||
$s['type'] = 'uri';
|
||||
$s['value'] = $this->calcURI($a[$this->rdf.'about'], $s['x_base']);
|
||||
}
|
||||
/* bnode */
|
||||
else {
|
||||
$s['type'] = 'bnode';
|
||||
if (isset($a[$this->rdf.'nodeID'])) {
|
||||
$s['value'] = '_:'.$a[$this->rdf.'nodeID'];
|
||||
}
|
||||
else {
|
||||
$s['value'] = $this->createBnodeID();
|
||||
}
|
||||
}
|
||||
/* sub-node */
|
||||
if ($this->state === 4) {
|
||||
$sup_s = $this->getParentS();
|
||||
/* new collection */
|
||||
if (isset($sup_s['o_is_coll']) && $sup_s['o_is_coll']) {
|
||||
$coll = array('value' => $this->createBnodeID(), 'type' => 'bnode', 'is_coll' => true, 'x_base' => $s['x_base'], 'x_lang' => $s['x_lang']);
|
||||
$this->addT($sup_s['value'], $sup_s['p'], $coll['value'], $sup_s['type'], $coll['type']);
|
||||
$this->addT($coll['value'], $this->rdf . 'first', $s['value'], $coll['type'], $s['type']);
|
||||
$this->pushS($coll);
|
||||
}
|
||||
/* new entry in existing coll */
|
||||
elseif (isset($sup_s['is_coll']) && $sup_s['is_coll']) {
|
||||
$coll = array('value' => $this->createBnodeID(), 'type' => 'bnode', 'is_coll' => true, 'x_base' => $s['x_base'], 'x_lang' => $s['x_lang']);
|
||||
$this->addT($sup_s['value'], $this->rdf . 'rest', $coll['value'], $sup_s['type'], $coll['type']);
|
||||
$this->addT($coll['value'], $this->rdf . 'first', $s['value'], $coll['type'], $s['type']);
|
||||
$this->pushS($coll);
|
||||
}
|
||||
/* normal sub-node */
|
||||
elseif(isset($sup_s['p']) && $sup_s['p']) {
|
||||
$this->addT($sup_s['value'], $sup_s['p'], $s['value'], $sup_s['type'], $s['type']);
|
||||
}
|
||||
}
|
||||
/* typed node */
|
||||
if ($t !== $this->rdf.'Description') {
|
||||
$this->addT($s['value'], $this->rdf.'type', $t, $s['type'], 'uri');
|
||||
}
|
||||
/* (additional) typing attr */
|
||||
if (isset($a[$this->rdf.'type'])) {
|
||||
$this->addT($s['value'], $this->rdf.'type', $a[$this->rdf.'type'], $s['type'], 'uri');
|
||||
}
|
||||
/* Seq|Bag|Alt */
|
||||
if (in_array($t, array($this->rdf.'Seq', $this->rdf.'Bag', $this->rdf.'Alt'))) {
|
||||
$s['is_con'] = true;
|
||||
}
|
||||
/* any other attrs (skip rdf and xml, except rdf:_, rdf:value, rdf:Seq) */
|
||||
foreach($a as $k => $v) {
|
||||
if (((strpos($k, $this->xml) === false) && (strpos($k, $this->rdf) === false)) || preg_match('/(\_[0-9]+|value|Seq|Bag|Alt|Statement|Property|List)$/', $k)) {
|
||||
if (strpos($k, ':')) {
|
||||
$this->addT($s['value'], $k, $v, $s['type'], 'literal', '', $s['x_lang']);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->pushS($s);
|
||||
$this->state = 2;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h2Open($t, $a) {
|
||||
$s = $this->getParentS();
|
||||
foreach (array('p_x_base', 'p_x_lang', 'p_id', 'o_is_coll') as $k) {
|
||||
unset($s[$k]);
|
||||
}
|
||||
/* base */
|
||||
if (isset($a[$this->xml.'base'])) {
|
||||
$s['p_x_base'] = $this->calcURI($a[$this->xml.'base'], $s['x_base']);
|
||||
}
|
||||
$b = isset($s['p_x_base']) && $s['p_x_base'] ? $s['p_x_base'] : $s['x_base'];
|
||||
/* lang */
|
||||
if (isset($a[$this->xml.'lang'])) {
|
||||
$s['p_x_lang'] = $a[$this->xml.'lang'];
|
||||
}
|
||||
$l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : $s['x_lang'];
|
||||
/* adjust li */
|
||||
if ($t === $this->rdf.'li') {
|
||||
$s['li_count']++;
|
||||
$t = $this->rdf.'_'.$s['li_count'];
|
||||
}
|
||||
/* set p */
|
||||
$s['p'] = $t;
|
||||
/* reification */
|
||||
if (isset($a[$this->rdf.'ID'])) {
|
||||
$s['p_id'] = $a[$this->rdf.'ID'];
|
||||
}
|
||||
$o = array('value' => '', 'type' => '', 'x_base' => $b, 'x_lang' => $l);
|
||||
/* resource/rdf:resource */
|
||||
if (isset($a['resource'])) {
|
||||
$a[$this->rdf . 'resource'] = $a['resource'];
|
||||
unset($a['resource']);
|
||||
}
|
||||
if (isset($a[$this->rdf.'resource'])) {
|
||||
$o['value'] = $this->calcURI($a[$this->rdf.'resource'], $b);
|
||||
$o['type'] = 'uri';
|
||||
$this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
|
||||
/* type */
|
||||
if (isset($a[$this->rdf.'type'])) {
|
||||
$this->addT($o['value'], $this->rdf.'type', $a[$this->rdf.'type'], 'uri', 'uri');
|
||||
}
|
||||
/* reification */
|
||||
if (isset($s['p_id'])) {
|
||||
$this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
|
||||
unset($s['p_id']);
|
||||
}
|
||||
$this->state = 3;
|
||||
}
|
||||
/* named bnode */
|
||||
elseif (isset($a[$this->rdf.'nodeID'])) {
|
||||
$o['value'] = '_:' . $a[$this->rdf.'nodeID'];
|
||||
$o['type'] = 'bnode';
|
||||
$this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
|
||||
$this->state = 3;
|
||||
/* reification */
|
||||
if (isset($s['p_id'])) {
|
||||
$this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
|
||||
}
|
||||
}
|
||||
/* parseType */
|
||||
elseif (isset($a[$this->rdf.'parseType'])) {
|
||||
if ($a[$this->rdf.'parseType'] === 'Literal') {
|
||||
$s['o_xml_level'] = 0;
|
||||
$s['o_xml_data'] = '';
|
||||
$s['p_xml_literal_level'] = 0;
|
||||
$s['ns'] = array();
|
||||
$this->state = 6;
|
||||
}
|
||||
elseif ($a[$this->rdf.'parseType'] === 'Resource') {
|
||||
$o['value'] = $this->createBnodeID();
|
||||
$o['type'] = 'bnode';
|
||||
$o['has_closing_tag'] = 0;
|
||||
$this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
|
||||
$this->pushS($o);
|
||||
/* reification */
|
||||
if (isset($s['p_id'])) {
|
||||
$this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
|
||||
unset($s['p_id']);
|
||||
}
|
||||
$this->state = 2;
|
||||
}
|
||||
elseif ($a[$this->rdf.'parseType'] === 'Collection') {
|
||||
$s['o_is_coll'] = true;
|
||||
$this->state = 4;
|
||||
}
|
||||
}
|
||||
/* sub-node or literal */
|
||||
else {
|
||||
$s['o_cdata'] = '';
|
||||
if (isset($a[$this->rdf.'datatype'])) {
|
||||
$s['o_datatype'] = $a[$this->rdf.'datatype'];
|
||||
}
|
||||
$this->state = 4;
|
||||
}
|
||||
/* any other attrs (skip rdf and xml) */
|
||||
foreach($a as $k => $v) {
|
||||
if (((strpos($k, $this->xml) === false) && (strpos($k, $this->rdf) === false)) || preg_match('/(\_[0-9]+|value)$/', $k)) {
|
||||
if (strpos($k, ':')) {
|
||||
if (!$o['value']) {
|
||||
$o['value'] = $this->createBnodeID();
|
||||
$o['type'] = 'bnode';
|
||||
$this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
|
||||
}
|
||||
/* reification */
|
||||
if (isset($s['p_id'])) {
|
||||
$this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
|
||||
unset($s['p_id']);
|
||||
}
|
||||
$this->addT($o['value'], $k, $v, $o['type'], 'literal');
|
||||
$this->state = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->updateS($s);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h4Open($t, $a) {
|
||||
return $this->h1Open($t, $a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h5Open($t, $a) {
|
||||
$this->state = 4;
|
||||
return $this->h4Open($t, $a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h6Open($t, $a) {
|
||||
$s = $this->getParentS();
|
||||
$data = isset($s['o_xml_data']) ? $s['o_xml_data'] : '';
|
||||
$ns = isset($s['ns']) ? $s['ns'] : array();
|
||||
$parts = $this->splitURI($t);
|
||||
if (count($parts) === 1) {
|
||||
$data .= '<'.$t;
|
||||
}
|
||||
else {
|
||||
$ns_uri = $parts[0];
|
||||
$name = $parts[1];
|
||||
if (!isset($this->nsp[$ns_uri])) {
|
||||
foreach ($this->nsp as $tmp1 => $tmp2) {
|
||||
if (strpos($t, $tmp1) === 0) {
|
||||
$ns_uri = $tmp1;
|
||||
$name = substr($t, strlen($tmp1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$nsp = $this->nsp[$ns_uri];
|
||||
$data .= $nsp ? '<' . $nsp . ':' . $name : '<' . $name;
|
||||
/* ns */
|
||||
if (!isset($ns[$nsp.'='.$ns_uri]) || !$ns[$nsp.'='.$ns_uri]) {
|
||||
$data .= $nsp ? ' xmlns:'.$nsp.'="'.$ns_uri.'"' : ' xmlns="'.$ns_uri.'"';
|
||||
$ns[$nsp.'='.$ns_uri] = true;
|
||||
$s['ns'] = $ns;
|
||||
}
|
||||
}
|
||||
foreach ($a as $k => $v) {
|
||||
$parts = $this->splitURI($k);
|
||||
if (count($parts) === 1) {
|
||||
$data .= ' '.$k.'="'.$v.'"';
|
||||
}
|
||||
else {
|
||||
$ns_uri = $parts[0];
|
||||
$name = $parts[1];
|
||||
$nsp = $this->nsp[$ns_uri];
|
||||
$data .= $nsp ? ' '.$nsp.':'.$name.'="'.$v.'"' : ' '.$name.'="'.$v.'"' ;
|
||||
}
|
||||
}
|
||||
$data .= '>';
|
||||
$s['o_xml_data'] = $data;
|
||||
$s['o_xml_level'] = isset($s['o_xml_level']) ? $s['o_xml_level'] + 1 : 1;
|
||||
if ($t == $s['p']) {/* xml container prop */
|
||||
$s['p_xml_literal_level'] = isset($s['p_xml_literal_level']) ? $s['p_xml_literal_level'] + 1 : 1;
|
||||
}
|
||||
$this->updateS($s);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h1Close($t) {/* end of doc */
|
||||
$this->state = 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h2Close($t) {/* expecting a prop, getting a close */
|
||||
if ($s = $this->getParentS()) {
|
||||
$has_closing_tag = (isset($s['has_closing_tag']) && !$s['has_closing_tag']) ? 0 : 1;
|
||||
$this->popS();
|
||||
$this->state = 5;
|
||||
if ($s = $this->getParentS()) {/* new s */
|
||||
if (!isset($s['p']) || !$s['p']) {/* p close after collection|parseType=Resource|node close after p close */
|
||||
$this->state = $this->s_count ? 4 : 1;
|
||||
if (!$has_closing_tag) {
|
||||
$this->state = 2;
|
||||
}
|
||||
}
|
||||
elseif (!$has_closing_tag) {
|
||||
$this->state = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h3Close($t) {/* p close */
|
||||
$this->state = 2;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h4Close($t) {/* empty p | pClose after cdata | pClose after collection */
|
||||
if ($s = $this->getParentS()) {
|
||||
$b = isset($s['p_x_base']) && $s['p_x_base'] ? $s['p_x_base'] : (isset($s['x_base']) ? $s['x_base'] : '');
|
||||
if (isset($s['is_coll']) && $s['is_coll']) {
|
||||
$this->addT($s['value'], $this->rdf . 'rest', $this->rdf . 'nil', $s['type'], 'uri');
|
||||
/* back to collection start */
|
||||
while ((!isset($s['p']) || ($s['p'] != $t))) {
|
||||
$sub_s = $s;
|
||||
$this->popS();
|
||||
$s = $this->getParentS();
|
||||
}
|
||||
/* reification */
|
||||
if (isset($s['p_id']) && $s['p_id']) {
|
||||
$this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $sub_s['value'], $s['type'], $sub_s['type']);
|
||||
}
|
||||
unset($s['p']);
|
||||
$this->updateS($s);
|
||||
}
|
||||
else {
|
||||
$dt = isset($s['o_datatype']) ? $s['o_datatype'] : '';
|
||||
$l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : (isset($s['x_lang']) ? $s['x_lang'] : '');
|
||||
$o = array('type' => 'literal', 'value' => $s['o_cdata']);
|
||||
$this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type'], $dt, $l);
|
||||
/* reification */
|
||||
if (isset($s['p_id']) && $s['p_id']) {
|
||||
$this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type'], $dt, $l);
|
||||
}
|
||||
unset($s['o_cdata']);
|
||||
unset($s['o_datatype']);
|
||||
unset($s['p']);
|
||||
$this->updateS($s);
|
||||
}
|
||||
$this->state = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h5Close($t) {/* p close */
|
||||
if ($s = $this->getParentS()) {
|
||||
unset($s['p']);
|
||||
$this->updateS($s);
|
||||
$this->state = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h6Close($t) {
|
||||
if ($s = $this->getParentS()) {
|
||||
$l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : (isset($s['x_lang']) ? $s['x_lang'] : '');
|
||||
$data = $s['o_xml_data'];
|
||||
$level = $s['o_xml_level'];
|
||||
if ($level === 0) {/* pClose */
|
||||
$this->addT($s['value'], $s['p'], trim($data, ' '), $s['type'], 'literal', $this->rdf.'XMLLiteral', $l);
|
||||
unset($s['o_xml_data']);
|
||||
$this->state = 2;
|
||||
}
|
||||
else {
|
||||
$parts = $this->splitURI($t);
|
||||
if (count($parts) == 1) {
|
||||
$data .= '</'.$t.'>';
|
||||
}
|
||||
else {
|
||||
$ns_uri = $parts[0];
|
||||
$name = $parts[1];
|
||||
if (!isset($this->nsp[$ns_uri])) {
|
||||
foreach ($this->nsp as $tmp1 => $tmp2) {
|
||||
if (strpos($t, $tmp1) === 0) {
|
||||
$ns_uri = $tmp1;
|
||||
$name = substr($t, strlen($tmp1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$nsp = $this->nsp[$ns_uri];
|
||||
$data .= $nsp ? '</'.$nsp.':'.$name.'>' : '</'.$name.'>';
|
||||
}
|
||||
$s['o_xml_data'] = $data;
|
||||
$s['o_xml_level'] = $level - 1;
|
||||
if ($t == $s['p']) {/* xml container prop */
|
||||
$s['p_xml_literal_level']--;
|
||||
}
|
||||
}
|
||||
$this->updateS($s);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h4Cdata($d) {
|
||||
if ($s = $this->getParentS()) {
|
||||
$s['o_cdata'] = isset($s['o_cdata']) ? $s['o_cdata'] . $d : $d;
|
||||
$this->updateS($s);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function h6Cdata($d) {
|
||||
if ($s = $this->getParentS()) {
|
||||
if (isset($s['o_xml_data']) || preg_match("/[\n\r]/", $d) || trim($d)) {
|
||||
$d = htmlspecialchars($d, ENT_NOQUOTES);
|
||||
$s['o_xml_data'] = isset($s['o_xml_data']) ? $s['o_xml_data'] . $d : $d;
|
||||
}
|
||||
$this->updateS($s);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
189
arc/parsers/ARC2_RSSParser.php
Normal file
189
arc/parsers/ARC2_RSSParser.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 RSS Parser
|
||||
author: Benjamin Nowack
|
||||
version: 2008-02-10
|
||||
*/
|
||||
|
||||
ARC2::inc('LegacyXMLParser');
|
||||
|
||||
class ARC2_RSSParser extends ARC2_LegacyXMLParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_RSSParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* reader */
|
||||
parent::__init();
|
||||
$this->triples = array();
|
||||
$this->target_encoding = '';
|
||||
$this->t_count = 0;
|
||||
$this->added_triples = array();
|
||||
$this->skip_dupes = false;
|
||||
$this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
|
||||
$this->bnode_id = 0;
|
||||
$this->cache = array();
|
||||
$this->allowCDataNodes = 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function done() {
|
||||
$this->extractRDF();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function setReader(&$reader) {
|
||||
$this->reader =& $reader;
|
||||
}
|
||||
|
||||
function createBnodeID(){
|
||||
$this->bnode_id++;
|
||||
return '_:' . $this->bnode_prefix . $this->bnode_id;
|
||||
}
|
||||
|
||||
function addT($t) {
|
||||
//if (!isset($t['o_datatype']))
|
||||
if ($this->skip_dupes) {
|
||||
$h = md5(serialize($t));
|
||||
if (!isset($this->added_triples[$h])) {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
$this->added_triples[$h] = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
}
|
||||
}
|
||||
|
||||
function getTriples() {
|
||||
return $this->v('triples', array());
|
||||
}
|
||||
|
||||
function countTriples() {
|
||||
return $this->t_count;
|
||||
}
|
||||
|
||||
function getSimpleIndex($flatten_objects = 1, $vals = '') {
|
||||
return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractRDF() {
|
||||
$index = $this->getNodeIndex();
|
||||
$this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
$this->rss = 'http://purl.org/rss/1.0/';
|
||||
$this->dc = 'http://purl.org/dc/elements/1.1/';
|
||||
$this->dct = 'http://purl.org/dc/terms/';
|
||||
$this->content = 'http://purl.org/rss/1.0/modules/content/';
|
||||
$this->enc = 'http://purl.oclc.org/net/rss_2.0/enc#';
|
||||
$this->mappings = array(
|
||||
'channel' => $this->rss . 'channel',
|
||||
'item' => $this->rss . 'item',
|
||||
'title' => $this->rss . 'title',
|
||||
'link' => $this->rss . 'link',
|
||||
'description' => $this->rss . 'description',
|
||||
'guid' => $this->dc . 'identifier',
|
||||
'author' => $this->dc . 'creator',
|
||||
'category' => $this->dc . 'subject',
|
||||
'pubDate' => $this->dc . 'date',
|
||||
'pubdate' => $this->dc . 'date',
|
||||
'source' => $this->dc . 'source',
|
||||
'enclosure' => $this->enc . 'enclosure',
|
||||
);
|
||||
$this->dt_props = array(
|
||||
$this->dc . 'identifier',
|
||||
$this->rss . 'link'
|
||||
);
|
||||
foreach ($index as $p_id => $nodes) {
|
||||
foreach ($nodes as $pos => $node) {
|
||||
$tag = $this->v('tag', '', $node);
|
||||
if ($tag == 'channel') {
|
||||
$struct = $this->extractChannel($index[$node['id']]);
|
||||
$triples = ARC2::getTriplesFromIndex($struct);
|
||||
foreach ($triples as $t) {
|
||||
$this->addT($t);
|
||||
}
|
||||
}
|
||||
elseif ($tag == 'item') {
|
||||
$struct = $this->extractItem($index[$node['id']]);
|
||||
$triples = ARC2::getTriplesFromIndex($struct);
|
||||
foreach ($triples as $t) {
|
||||
$this->addT($t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function extractChannel($els) {
|
||||
$res = array($this->rdf . 'type' => array(array('value' => $this->rss . 'channel', 'type' => 'uri')));
|
||||
$res = array_merge($res, $this->extractProps($els, 'channel'));
|
||||
return array($res[$this->rss . 'link'][0]['value'] => $res);
|
||||
}
|
||||
|
||||
function extractItem($els) {
|
||||
$res = array($this->rdf . 'type' => array(array('value' => $this->rss . 'item', 'type' => 'uri')));
|
||||
$res = array_merge($res, $this->extractProps($els, 'item'));
|
||||
if (isset($res[$this->rss . 'link'])) return array($res[$this->rss . 'link'][0]['value'] => $res);
|
||||
if (isset($res[$this->dc . 'identifier'])) return array($res[$this->dc . 'identifier'][0]['value'] => $res);
|
||||
}
|
||||
|
||||
function extractProps($els, $container) {
|
||||
$res = array();
|
||||
foreach ($els as $info) {
|
||||
/* key */
|
||||
$tag = $info['tag'];
|
||||
if (!preg_match('/^[a-z0-9]+\:/i', $tag)) {
|
||||
$k = isset($this->mappings[$tag]) ? $this->mappings[$tag] : '';
|
||||
}
|
||||
else {
|
||||
$k = $tag;
|
||||
}
|
||||
if (($container == 'channel') && ($k == $this->rss . 'item')) continue;
|
||||
/* val */
|
||||
$v = $info['cdata'];
|
||||
if (!$v) $v = $this->v('url', '', $info['a']);
|
||||
if (!$v) $v = $this->v('href', '', $info['a']);
|
||||
/* prop */
|
||||
if ($k) {
|
||||
/* enclosure handling */
|
||||
if ($k == $this->enc . 'enclosure') {
|
||||
$sub_res = array();
|
||||
foreach (array('length', 'type') as $attr) {
|
||||
if ($attr_v = $this->v($attr, 0, $info['a'])) {
|
||||
$sub_res[$this->enc . $attr] = array(array('value' => $attr_v, 'type' => 'literal'));
|
||||
}
|
||||
}
|
||||
$struct[$v] = $sub_res;
|
||||
}
|
||||
/* date handling */
|
||||
if (in_array($k, array($this->dc . 'date', $this->dct . 'modified'))) {
|
||||
if (!preg_match('/^[0-9]{4}/', $v) && ($sub_v = strtotime($v)) && ($sub_v != -1)) {
|
||||
$tz = date('Z', $sub_v); /* timezone offset */
|
||||
$sub_v -= $tz; /* utc */
|
||||
$v = date('Y-m-d\TH:i:s\Z', $sub_v);
|
||||
}
|
||||
}
|
||||
if (!isset($res[$k])) $res[$k] = array();
|
||||
$res[$k][] = array('value' => $v, 'type' => in_array($k, $this->dt_props) || !preg_match('/^[a-z0-9]+\:[^\s]+$/is', $v) ? 'literal' : 'uri');
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
|
||||
}
|
||||
67
arc/parsers/ARC2_SGAJSONParser.php
Normal file
67
arc/parsers/ARC2_SGAJSONParser.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 SG API JSON Parser
|
||||
author: Benjamin Nowack
|
||||
version: 2008-07-17 (Tweak: Moved re-usable code to new ARC2_JSONParser)
|
||||
*/
|
||||
|
||||
ARC2::inc('JSONParser');
|
||||
|
||||
class ARC2_SGAJSONParser extends ARC2_JSONParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_SGAJSONParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* reader */
|
||||
parent::__init();
|
||||
$this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
$this->nsp = array($this->rdf => 'rdf');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function done() {
|
||||
$this->extractRDF();
|
||||
}
|
||||
|
||||
function extractRDF() {
|
||||
$s = $this->getContext();
|
||||
$os = $this->getURLs($this->struct);
|
||||
foreach ($os as $o) {
|
||||
if ($o != $s) $this->addT($s, 'http://www.w3.org/2000/01/rdf-schema#seeAlso', $o, 'uri', 'uri');
|
||||
}
|
||||
}
|
||||
|
||||
function getContext() {
|
||||
if (!isset($this->struct['canonical_mapping'])) return '';
|
||||
foreach ($this->struct['canonical_mapping'] as $k => $v) return $v;
|
||||
}
|
||||
|
||||
function getURLs($struct) {
|
||||
$r =array();
|
||||
if (is_array($struct)) {
|
||||
foreach ($struct as $k => $v) {
|
||||
if (preg_match('/^http:\/\//', $k) && !in_array($k, $r)) $r[] = $k;
|
||||
$sub_r = $this->getURLs($v);
|
||||
foreach ($sub_r as $sub_v) {
|
||||
if (!in_array($sub_v, $r)) $r[] = $sub_v;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (preg_match('/^http:\/\//', $struct) && !in_array($struct, $r)) {
|
||||
$r[] = $struct;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
776
arc/parsers/ARC2_SPARQLParser.php
Normal file
776
arc/parsers/ARC2_SPARQLParser.php
Normal file
@@ -0,0 +1,776 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 SPARQL Parser
|
||||
author: Benjamin Nowack
|
||||
version: 2009-10-05
|
||||
*/
|
||||
|
||||
ARC2::inc('TurtleParser');
|
||||
|
||||
class ARC2_SPARQLParser extends ARC2_TurtleParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_SPARQLParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
|
||||
$this->bnode_id = 0;
|
||||
$this->bnode_pattern_index = array('patterns' => array(), 'bnodes' => array());
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function parse($q, $src = '') {
|
||||
$this->setDefaultPrefixes();
|
||||
$this->base = $src ? $this->calcBase($src) : ARC2::getRequestURI();
|
||||
$this->r = array(
|
||||
'base' => '',
|
||||
'vars' => array(),
|
||||
'prefixes' => array()
|
||||
);
|
||||
$this->unparsed_code = $q;
|
||||
list($r, $v) = $this->xQuery($q);
|
||||
if ($r) {
|
||||
$this->r['query'] = $r;
|
||||
$this->unparsed_code = trim($v);
|
||||
}
|
||||
elseif (!$this->getErrors() && !$this->unparsed_code) {
|
||||
$this->addError('Query not properly closed');
|
||||
}
|
||||
$this->r['prefixes'] = $this->prefixes;
|
||||
$this->r['base'] = $this->base;
|
||||
/* remove trailing comments */
|
||||
while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $this->unparsed_code, $m)) $this->unparsed_code = $m[2];
|
||||
if ($this->unparsed_code && !$this->getErrors()) {
|
||||
$rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
|
||||
$msg = trim($rest) ? 'Could not properly handle "' . $rest . '"' : 'Syntax error, probably an incomplete pattern';
|
||||
$this->addError($msg);
|
||||
}
|
||||
}
|
||||
|
||||
function getQueryInfos() {
|
||||
return $this->v('r', array());
|
||||
}
|
||||
|
||||
/* 1 */
|
||||
|
||||
function xQuery($v) {
|
||||
list($r, $v) = $this->xPrologue($v);
|
||||
foreach (array('Select', 'Construct', 'Describe', 'Ask') as $type) {
|
||||
$m = 'x' . $type . 'Query';
|
||||
if ((list($r, $v) = $this->$m($v)) && $r) {
|
||||
return array($r, $v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 2 */
|
||||
|
||||
function xPrologue($v) {
|
||||
$r = 0;
|
||||
if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
|
||||
$this->base = $sub_r;
|
||||
$r = 1;
|
||||
}
|
||||
while ((list($sub_r, $v) = $this->xPrefixDecl($v)) && $sub_r) {
|
||||
$this->prefixes[$sub_r['prefix']] = $sub_r['uri'];
|
||||
$r = 1;
|
||||
}
|
||||
return array($r, $v);
|
||||
}
|
||||
|
||||
/* 5.. */
|
||||
|
||||
function xSelectQuery($v) {
|
||||
if ($sub_r = $this->x('SELECT\s+', $v)) {
|
||||
$r = array(
|
||||
'type' => 'select',
|
||||
'result_vars' => array(),
|
||||
'dataset' => array(),
|
||||
);
|
||||
$all_vars = 0;
|
||||
$sub_v = $sub_r[1];
|
||||
/* distinct, reduced */
|
||||
if ($sub_r = $this->x('(DISTINCT|REDUCED)\s+', $sub_v)) {
|
||||
$r[strtolower($sub_r[1])] = 1;
|
||||
$sub_v = $sub_r[2];
|
||||
}
|
||||
/* result vars */
|
||||
if ($sub_r = $this->x('\*\s+', $sub_v)) {
|
||||
$all_vars = 1;
|
||||
$sub_v = $sub_r[1];
|
||||
}
|
||||
else {
|
||||
while ((list($sub_r, $sub_v) = $this->xResultVar($sub_v)) && $sub_r) {
|
||||
$r['result_vars'][] = $sub_r;
|
||||
}
|
||||
}
|
||||
if (!$all_vars && !count($r['result_vars'])) {
|
||||
$this->addError('No result bindings specified.');
|
||||
}
|
||||
/* dataset */
|
||||
while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
|
||||
$r['dataset'][] = $sub_r;
|
||||
}
|
||||
/* where */
|
||||
if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
|
||||
$r['pattern'] = $sub_r;
|
||||
}
|
||||
else {
|
||||
return array(0, $v);
|
||||
}
|
||||
/* solution modifier */
|
||||
if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
|
||||
$r = array_merge($r, $sub_r);
|
||||
}
|
||||
/* all vars */
|
||||
if ($all_vars) {
|
||||
foreach ($this->r['vars'] as $var) {
|
||||
$r['result_vars'][] = array('var' => $var, 'aggregate' => 0, 'alias' => '');
|
||||
}
|
||||
if (!$r['result_vars']) {
|
||||
$r['result_vars'][] = '*';
|
||||
}
|
||||
}
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
function xResultVar($v) {
|
||||
return $this->xVar($v);
|
||||
}
|
||||
|
||||
/* 6.. */
|
||||
|
||||
function xConstructQuery($v) {
|
||||
if ($sub_r = $this->x('CONSTRUCT\s*', $v)) {
|
||||
$r = array(
|
||||
'type' => 'construct',
|
||||
'dataset' => array(),
|
||||
);
|
||||
$sub_v = $sub_r[1];
|
||||
/* construct template */
|
||||
if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
|
||||
$r['construct_triples'] = $sub_r;
|
||||
}
|
||||
else {
|
||||
$this->addError('Construct Template not found');
|
||||
return array(0, $v);
|
||||
}
|
||||
/* dataset */
|
||||
while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
|
||||
$r['dataset'][] = $sub_r;
|
||||
}
|
||||
/* where */
|
||||
if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
|
||||
$r['pattern'] = $sub_r;
|
||||
}
|
||||
else {
|
||||
return array(0, $v);
|
||||
}
|
||||
/* solution modifier */
|
||||
if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
|
||||
$r = array_merge($r, $sub_r);
|
||||
}
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 7.. */
|
||||
|
||||
function xDescribeQuery($v) {
|
||||
if ($sub_r = $this->x('DESCRIBE\s+', $v)) {
|
||||
$r = array(
|
||||
'type' => 'describe',
|
||||
'result_vars' => array(),
|
||||
'result_uris' => array(),
|
||||
'dataset' => array(),
|
||||
);
|
||||
$sub_v = $sub_r[1];
|
||||
$all_vars = 0;
|
||||
/* result vars/uris */
|
||||
if ($sub_r = $this->x('\*\s+', $sub_v)) {
|
||||
$all_vars = 1;
|
||||
$sub_v = $sub_r[1];
|
||||
}
|
||||
else {
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ((list($sub_r, $sub_v) = $this->xResultVar($sub_v)) && $sub_r) {
|
||||
$r['result_vars'][] = $sub_r;
|
||||
$proceed = 1;
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
|
||||
$r['result_uris'][] = $sub_r;
|
||||
$proceed =1;
|
||||
}
|
||||
} while ($proceed);
|
||||
}
|
||||
if (!$all_vars && !count($r['result_vars']) && !count($r['result_uris'])) {
|
||||
$this->addError('No result bindings specified.');
|
||||
}
|
||||
/* dataset */
|
||||
while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
|
||||
$r['dataset'][] = $sub_r;
|
||||
}
|
||||
/* where */
|
||||
if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
|
||||
$r['pattern'] = $sub_r;
|
||||
}
|
||||
/* solution modifier */
|
||||
if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
|
||||
$r = array_merge($r, $sub_r);
|
||||
}
|
||||
/* all vars */
|
||||
if ($all_vars) {
|
||||
foreach ($this->r['vars'] as $var) {
|
||||
$r['result_vars'][] = array('var' => $var, 'aggregate' => 0, 'alias' => '');
|
||||
}
|
||||
}
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 8.. */
|
||||
|
||||
function xAskQuery($v) {
|
||||
if ($sub_r = $this->x('ASK\s+', $v)) {
|
||||
$r = array(
|
||||
'type' => 'ask',
|
||||
'dataset' => array(),
|
||||
);
|
||||
$sub_v = $sub_r[1];
|
||||
/* dataset */
|
||||
while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
|
||||
$r['dataset'][] = $sub_r;
|
||||
}
|
||||
/* where */
|
||||
if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
|
||||
$r['pattern'] = $sub_r;
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
else {
|
||||
$this->addError('Missing or invalid WHERE clause.');
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 9, 10, 11, 12 */
|
||||
|
||||
function xDatasetClause($v) {
|
||||
if ($r = $this->x('FROM(\s+NAMED)?\s+', $v)) {
|
||||
$named = $r[1] ? 1 : 0;
|
||||
if ((list($r, $sub_v) = $this->xIRIref($r[2])) && $r) {
|
||||
return array(array('graph' => $r, 'named' => $named), $sub_v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 13 */
|
||||
|
||||
function xWhereClause($v) {
|
||||
if ($r = $this->x('(WHERE)?', $v)) {
|
||||
$v = $r[2];
|
||||
}
|
||||
if ((list($r, $v) = $this->xGroupGraphPattern($v)) && $r) {
|
||||
return array($r, $v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 14, 15 */
|
||||
|
||||
function xSolutionModifier($v) {
|
||||
$r = array();
|
||||
if ((list($sub_r, $sub_v) = $this->xOrderClause($v)) && $sub_r) {
|
||||
$r['order_infos'] = $sub_r;
|
||||
}
|
||||
while ((list($sub_r, $sub_v) = $this->xLimitOrOffsetClause($sub_v)) && $sub_r) {
|
||||
$r = array_merge($r, $sub_r);
|
||||
}
|
||||
return ($v == $sub_v) ? array(0, $v) : array($r, $sub_v);
|
||||
}
|
||||
|
||||
/* 18, 19 */
|
||||
|
||||
function xLimitOrOffsetClause($v) {
|
||||
if ($sub_r = $this->x('(LIMIT|OFFSET)', $v)) {
|
||||
$key = strtolower($sub_r[1]);
|
||||
$sub_v = $sub_r[2];
|
||||
if ((list($sub_r, $sub_v) = $this->xINTEGER($sub_v)) && ($sub_r !== false)) {
|
||||
return array(array($key =>$sub_r), $sub_v);
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xPlaceholder($sub_v)) && ($sub_r !== false)) {
|
||||
return array(array($key =>$sub_r), $sub_v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 16 */
|
||||
|
||||
function xOrderClause($v) {
|
||||
if ($sub_r = $this->x('ORDER BY\s+', $v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$r = array();
|
||||
while ((list($sub_r, $sub_v) = $this->xOrderCondition($sub_v)) && $sub_r) {
|
||||
$r[] = $sub_r;
|
||||
}
|
||||
if (count($r)) {
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
else {
|
||||
$this->addError('No order conditions specified.');
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 17, 27 */
|
||||
|
||||
function xOrderCondition($v) {
|
||||
if ($sub_r = $this->x('(ASC|DESC)', $v)) {
|
||||
$dir = strtolower($sub_r[1]);
|
||||
$sub_v = $sub_r[2];
|
||||
if ((list($sub_r, $sub_v) = $this->xBrackettedExpression($sub_v)) && $sub_r) {
|
||||
$sub_r['direction'] = $dir;
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
|
||||
$sub_r['direction'] = 'asc';
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xBrackettedExpression($v)) && $sub_r) {
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xBuiltInCall($v)) && $sub_r) {
|
||||
$sub_r['direction'] = 'asc';
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xFunctionCall($v)) && $sub_r) {
|
||||
$sub_r['direction'] = 'asc';
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 20 */
|
||||
|
||||
function xGroupGraphPattern($v) {
|
||||
$pattern_id = substr(md5(uniqid(rand())), 0, 4);
|
||||
if ($sub_r = $this->x('\{', $v)) {
|
||||
$r = array('type' => 'group', 'patterns' => array());
|
||||
$sub_v = $sub_r[1];
|
||||
if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_v)) && $sub_r) {
|
||||
$this->indexBnodes($sub_r, $pattern_id);
|
||||
$r['patterns'][] = array('type' => 'triples', 'patterns' => $sub_r);
|
||||
}
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ((list($sub_r, $sub_v) = $this->xGraphPatternNotTriples($sub_v)) && $sub_r) {
|
||||
$r['patterns'][] = $sub_r;
|
||||
$pattern_id = substr(md5(uniqid(rand())), 0, 4);
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xFilter($sub_v)) && $sub_r) {
|
||||
$r['patterns'][] = array('type' => 'filter', 'constraint' => $sub_r);
|
||||
$proceed = 1;
|
||||
}
|
||||
if ($sub_r = $this->x('\.', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_v)) && $sub_r) {
|
||||
$this->indexBnodes($sub_r, $pattern_id);
|
||||
$r['patterns'][] = array('type' => 'triples', 'patterns' => $sub_r);
|
||||
$proceed = 1;
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xPlaceholder($sub_v)) && $sub_r) {
|
||||
$r['patterns'][] = $sub_r;
|
||||
$proceed = 1;
|
||||
}
|
||||
} while ($proceed);
|
||||
if ($sub_r = $this->x('\}', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
$rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($sub_v, 0, 30));
|
||||
$this->addError('Incomplete or invalid Group Graph pattern. Could not handle "' . $rest . '"');
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
function indexBnodes($triples, $pattern_id) {
|
||||
$index_id = count($this->bnode_pattern_index['patterns']);
|
||||
$index_id = $pattern_id;
|
||||
$this->bnode_pattern_index['patterns'][] = $triples;
|
||||
foreach ($triples as $t) {
|
||||
foreach (array('s', 'p', 'o') as $term) {
|
||||
if ($t[$term . '_type'] == 'bnode') {
|
||||
$val = $t[$term];
|
||||
if (isset($this->bnode_pattern_index['bnodes'][$val]) && ($this->bnode_pattern_index['bnodes'][$val] != $index_id)) {
|
||||
$this->addError('Re-used bnode label "' .$val. '" across graph patterns');
|
||||
}
|
||||
else {
|
||||
$this->bnode_pattern_index['bnodes'][$val] = $index_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 22.., 25.. */
|
||||
|
||||
function xGraphPatternNotTriples($v) {
|
||||
if ((list($sub_r, $sub_v) = $this->xOptionalGraphPattern($v)) && $sub_r) {
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xGraphGraphPattern($v)) && $sub_r) {
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
$r = array('type' => 'union', 'patterns' => array());
|
||||
$sub_v = $v;
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
|
||||
$r['patterns'][] = $sub_r;
|
||||
if ($sub_r = $this->x('UNION', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
$pc = count($r['patterns']);
|
||||
if ($pc == 1) {
|
||||
return array($r['patterns'][0], $sub_v);
|
||||
}
|
||||
elseif ($pc > 1) {
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 23 */
|
||||
|
||||
function xOptionalGraphPattern($v) {
|
||||
if ($sub_r = $this->x('OPTIONAL', $v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
|
||||
return array(array('type' => 'optional', 'patterns' => $sub_r['patterns']), $sub_v);
|
||||
}
|
||||
$this->addError('Missing or invalid Group Graph Pattern after OPTIONAL');
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 24.. */
|
||||
|
||||
function xGraphGraphPattern($v) {
|
||||
if ($sub_r = $this->x('GRAPH', $v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$r = array('type' => 'graph', 'var' => '', 'uri' => '', 'patterns' => array());
|
||||
if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
|
||||
$r['var'] = $sub_r;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
|
||||
$r['uri'] = $sub_r;
|
||||
}
|
||||
if ($r['var'] || $r['uri']) {
|
||||
if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
|
||||
$r['patterns'][] = $sub_r;
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
$this->addError('Missing or invalid Graph Pattern');
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 26.., 27.. */
|
||||
|
||||
function xFilter($v) {
|
||||
if ($r = $this->x('FILTER', $v)) {
|
||||
$sub_v = $r[1];
|
||||
if ((list($r, $sub_v) = $this->xBrackettedExpression($sub_v)) && $r) {
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
if ((list($r, $sub_v) = $this->xBuiltInCall($sub_v)) && $r) {
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
if ((list($r, $sub_v) = $this->xFunctionCall($sub_v)) && $r) {
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
$this->addError('Incomplete FILTER');
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 28.. */
|
||||
|
||||
function xFunctionCall($v) {
|
||||
if ((list($r, $sub_v) = $this->xIRIref($v)) && $r) {
|
||||
if ((list($sub_r, $sub_v) = $this->xArgList($sub_v)) && $sub_r) {
|
||||
return array(array('type' => 'function_call', 'uri' => $r, 'args' => $sub_r), $sub_v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 29 */
|
||||
|
||||
function xArgList($v) {
|
||||
$r = array();
|
||||
$sub_v = $v;
|
||||
$closed = 0;
|
||||
if ($sub_r = $this->x('\(', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ((list($sub_r, $sub_v) = $this->xExpression($sub_v)) && $sub_r) {
|
||||
$r[] = $sub_r;
|
||||
if ($sub_r = $this->x('\,', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
if ($sub_r = $this->x('\)', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$closed = 1;
|
||||
$proceed = 0;
|
||||
}
|
||||
} while ($proceed);
|
||||
}
|
||||
return $closed ? array($r, $sub_v) : array(0, $v);
|
||||
}
|
||||
|
||||
/* 30, 31 */
|
||||
|
||||
function xConstructTemplate($v) {
|
||||
if ($sub_r = $this->x('\{', $v)) {
|
||||
$r = array();
|
||||
if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_r[1])) && is_array($sub_r)) {
|
||||
$r = $sub_r;
|
||||
}
|
||||
if ($sub_r = $this->x('\}', $sub_v)) {
|
||||
return array($r, $sub_r[1]);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 46, 47 */
|
||||
|
||||
function xExpression($v) {
|
||||
if ((list($sub_r, $sub_v) = $this->xConditionalAndExpression($v)) && $sub_r) {
|
||||
$r = array('type' => 'expression', 'sub_type' => 'or', 'patterns' => array($sub_r));
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ($sub_r = $this->x('\|\|', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
if ((list($sub_r, $sub_v) = $this->xConditionalAndExpression($sub_v)) && $sub_r) {
|
||||
$r['patterns'][] = $sub_r;
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 48.., 49.. */
|
||||
|
||||
function xConditionalAndExpression($v) {
|
||||
if ((list($sub_r, $sub_v) = $this->xRelationalExpression($v)) && $sub_r) {
|
||||
$r = array('type' => 'expression', 'sub_type' => 'and', 'patterns' => array($sub_r));
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ($sub_r = $this->x('\&\&', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
if ((list($sub_r, $sub_v) = $this->xRelationalExpression($sub_v)) && $sub_r) {
|
||||
$r['patterns'][] = $sub_r;
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 50, 51 */
|
||||
|
||||
function xRelationalExpression($v) {
|
||||
if ((list($sub_r, $sub_v) = $this->xAdditiveExpression($v)) && $sub_r) {
|
||||
$r = array('type' => 'expression', 'sub_type' => 'relational', 'patterns' => array($sub_r));
|
||||
do {
|
||||
$proceed = 0;
|
||||
/* don't mistake '<' + uriref with '<'-operator ("longest token" rule) */
|
||||
if ((list($sub_r, $sub_v) = $this->xIRI_REF($sub_v)) && $sub_r) {
|
||||
$this->addError('Expected operator, found IRIref: "'.$sub_r.'".');
|
||||
}
|
||||
if ($sub_r = $this->x('(\!\=|\=\=|\=|\<\=|\>\=|\<|\>)', $sub_v)) {
|
||||
$op = $sub_r[1];
|
||||
$sub_v = $sub_r[2];
|
||||
$r['operator'] = $op;
|
||||
if ((list($sub_r, $sub_v) = $this->xAdditiveExpression($sub_v)) && $sub_r) {
|
||||
//$sub_r['operator'] = $op;
|
||||
$r['patterns'][] = $sub_r;
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 52 */
|
||||
|
||||
function xAdditiveExpression($v) {
|
||||
if ((list($sub_r, $sub_v) = $this->xMultiplicativeExpression($v)) && $sub_r) {
|
||||
$r = array('type' => 'expression', 'sub_type' => 'additive', 'patterns' => array($sub_r));
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ($sub_r = $this->x('(\+|\-)', $sub_v)) {
|
||||
$op = $sub_r[1];
|
||||
$sub_v = $sub_r[2];
|
||||
if ((list($sub_r, $sub_v) = $this->xMultiplicativeExpression($sub_v)) && $sub_r) {
|
||||
$sub_r['operator'] = $op;
|
||||
$r['patterns'][] = $sub_r;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xNumericLiteral($sub_v)) && $sub_r) {
|
||||
$r['patterns'][] = array('type' => 'numeric', 'operator' => $op, 'value' => $sub_r);
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
//return array($r, $sub_v);
|
||||
return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 53 */
|
||||
|
||||
function xMultiplicativeExpression($v) {
|
||||
if ((list($sub_r, $sub_v) = $this->xUnaryExpression($v)) && $sub_r) {
|
||||
$r = array('type' => 'expression', 'sub_type' => 'multiplicative', 'patterns' => array($sub_r));
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ($sub_r = $this->x('(\*|\/)', $sub_v)) {
|
||||
$op = $sub_r[1];
|
||||
$sub_v = $sub_r[2];
|
||||
if ((list($sub_r, $sub_v) = $this->xUnaryExpression($sub_v)) && $sub_r) {
|
||||
$sub_r['operator'] = $op;
|
||||
$r['patterns'][] = $sub_r;
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 54 */
|
||||
|
||||
function xUnaryExpression($v) {
|
||||
$sub_v = $v;
|
||||
$op = '';
|
||||
if ($sub_r = $this->x('(\!|\+|\-)', $sub_v)) {
|
||||
$op = $sub_r[1];
|
||||
$sub_v = $sub_r[2];
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xPrimaryExpression($sub_v)) && $sub_r) {
|
||||
if (!is_array($sub_r)) {
|
||||
$sub_r = array('type' => 'unary', 'expression' => $sub_r);
|
||||
}
|
||||
elseif ($sub_op = $this->v1('operator', '', $sub_r)) {
|
||||
$ops = array('!!' => '', '++' => '+', '--' => '+', '+-' => '-', '-+' => '-');
|
||||
$op = isset($ops[$op . $sub_op]) ? $ops[$op . $sub_op] : $op . $sub_op;
|
||||
}
|
||||
$sub_r['operator'] = $op;
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 55 */
|
||||
|
||||
function xPrimaryExpression($v) {
|
||||
foreach (array('BrackettedExpression', 'BuiltInCall', 'IRIrefOrFunction', 'RDFLiteral', 'NumericLiteral', 'BooleanLiteral', 'Var', 'Placeholder') as $type) {
|
||||
$m = 'x' . $type;
|
||||
if ((list($sub_r, $sub_v) = $this->$m($v)) && $sub_r) {
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 56 */
|
||||
|
||||
function xBrackettedExpression($v) {
|
||||
if ($r = $this->x('\(', $v)) {
|
||||
if ((list($r, $sub_v) = $this->xExpression($r[1])) && $r) {
|
||||
if ($sub_r = $this->x('\)', $sub_v)) {
|
||||
return array($r, $sub_r[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 57.., 58.. */
|
||||
|
||||
function xBuiltInCall($v) {
|
||||
if ($sub_r = $this->x('(str|lang|langmatches|datatype|bound|sameterm|isiri|isuri|isblank|isliteral|regex)\s*\(', $v)) {
|
||||
$r = array('type' => 'built_in_call', 'call' => strtolower($sub_r[1]));
|
||||
if ((list($sub_r, $sub_v) = $this->xArgList('(' . $sub_r[2])) && is_array($sub_r)) {
|
||||
$r['args'] = $sub_r;
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 59.. */
|
||||
|
||||
function xIRIrefOrFunction($v) {
|
||||
if ((list($r, $v) = $this->xIRIref($v)) && $r) {
|
||||
if ((list($sub_r, $sub_v) = $this->xArgList($v)) && is_array($sub_r)) {
|
||||
return array(array('type' => 'function', 'uri' => $r, 'args' => $sub_r), $sub_v);
|
||||
}
|
||||
return array(array('type' => 'uri', 'uri' => $r), $sub_v);
|
||||
}
|
||||
}
|
||||
|
||||
/* 70.. */
|
||||
|
||||
function xIRI_REF($v) {
|
||||
if (($r = $this->x('\<(\$\{[^\>]*\})\>', $v)) && ($sub_r = $this->xPlaceholder($r[1]))) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
elseif ($r = $this->x('\<([^\<\>\s\"\|\^`]*)\>', $v)) {
|
||||
return array($r[1] ? $r[1] : true, $r[2]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
}
|
||||
214
arc/parsers/ARC2_SPARQLPlusParser.php
Normal file
214
arc/parsers/ARC2_SPARQLPlusParser.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 SPARQL+ Parser (SPARQL + Aggregates + LOAD + INSERT + DELETE)
|
||||
author: Benjamin Nowack
|
||||
version: 2008-05-30 (Tweak: CONSTRUCT keyword is now optional)
|
||||
*/
|
||||
|
||||
ARC2::inc('SPARQLParser');
|
||||
|
||||
class ARC2_SPARQLPlusParser extends ARC2_SPARQLParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_SPARQLPlusParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* +1 */
|
||||
|
||||
function xQuery($v) {
|
||||
list($r, $v) = $this->xPrologue($v);
|
||||
foreach (array('Select', 'Construct', 'Describe', 'Ask', 'Insert', 'Delete', 'Load') as $type) {
|
||||
$m = 'x' . $type . 'Query';
|
||||
if ((list($r, $v) = $this->$m($v)) && $r) {
|
||||
return array($r, $v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* +3 */
|
||||
|
||||
function xResultVar($v) {
|
||||
$aggregate = '';
|
||||
/* aggregate */
|
||||
if ($sub_r = $this->x('\(?(AVG|COUNT|MAX|MIN|SUM)\s*\(\s*([^\)]+)\)\s+AS\s+([^\s\)]+)\)?', $v)) {
|
||||
$aggregate = $sub_r[1];
|
||||
$result_var = $sub_r[3];
|
||||
$v = $sub_r[2] . $sub_r[4];
|
||||
}
|
||||
if ($sub_r && (list($sub_r, $sub_v) = $this->xVar($result_var)) && $sub_r) {
|
||||
$result_var = $sub_r['value'];
|
||||
}
|
||||
/* * or var */
|
||||
if ((list($sub_r, $sub_v) = $this->x('\*', $v)) && $sub_r) {
|
||||
return array(array('var' => $sub_r['value'], 'aggregate' => $aggregate, 'alias' => $aggregate ? $result_var : ''), $sub_v);
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
|
||||
return array(array('var' => $sub_r['value'], 'aggregate' => $aggregate, 'alias' => $aggregate ? $result_var : ''), $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* +4 */
|
||||
|
||||
function xLoadQuery($v) {
|
||||
if ($sub_r = $this->x('LOAD\s+', $v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
|
||||
$r = array('type' => 'load', 'url' => $sub_r, 'target_graph' => '');
|
||||
if ($sub_r = $this->x('INTO\s+', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
|
||||
$r['target_graph'] = $sub_r;
|
||||
}
|
||||
}
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* +5 */
|
||||
|
||||
function xInsertQuery($v) {
|
||||
if ($sub_r = $this->x('INSERT\s+', $v)) {
|
||||
$r = array(
|
||||
'type' => 'insert',
|
||||
'dataset' => array(),
|
||||
);
|
||||
$sub_v = $sub_r[1];
|
||||
/* target */
|
||||
if ($sub_r = $this->x('INTO\s+', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
|
||||
$r['target_graph'] = $sub_r;
|
||||
/* CONSTRUCT keyword, optional */
|
||||
if ($sub_r = $this->x('CONSTRUCT\s+', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
}
|
||||
/* construct template */
|
||||
if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
|
||||
$r['construct_triples'] = $sub_r;
|
||||
}
|
||||
else {
|
||||
$this->addError('Construct Template not found');
|
||||
return array(0, $v);
|
||||
}
|
||||
/* dataset */
|
||||
while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
|
||||
$r['dataset'][] = $sub_r;
|
||||
}
|
||||
/* where */
|
||||
if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
|
||||
$r['pattern'] = $sub_r;
|
||||
}
|
||||
/* solution modifier */
|
||||
if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
|
||||
$r = array_merge($r, $sub_r);
|
||||
}
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* +6 */
|
||||
|
||||
function xDeleteQuery($v) {
|
||||
if ($sub_r = $this->x('DELETE\s+', $v)) {
|
||||
$r = array(
|
||||
'type' => 'delete',
|
||||
'target_graphs' => array()
|
||||
);
|
||||
$sub_v = $sub_r[1];
|
||||
/* target */
|
||||
do {
|
||||
$proceed = false;
|
||||
if ($sub_r = $this->x('FROM\s+', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
|
||||
$r['target_graphs'][] = $sub_r;
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
/* CONSTRUCT keyword, optional */
|
||||
if ($sub_r = $this->x('CONSTRUCT\s+', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
}
|
||||
/* construct template */
|
||||
if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
|
||||
$r['construct_triples'] = $sub_r;
|
||||
/* dataset */
|
||||
while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
|
||||
$r['dataset'][] = $sub_r;
|
||||
}
|
||||
/* where */
|
||||
if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
|
||||
$r['pattern'] = $sub_r;
|
||||
}
|
||||
/* solution modifier */
|
||||
if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
|
||||
$r = array_merge($r, $sub_r);
|
||||
}
|
||||
}
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* +7 */
|
||||
|
||||
function xSolutionModifier($v) {
|
||||
$r = array();
|
||||
if ((list($sub_r, $sub_v) = $this->xGroupClause($v)) && $sub_r) {
|
||||
$r['group_infos'] = $sub_r;
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xOrderClause($sub_v)) && $sub_r) {
|
||||
$r['order_infos'] = $sub_r;
|
||||
}
|
||||
while ((list($sub_r, $sub_v) = $this->xLimitOrOffsetClause($sub_v)) && $sub_r) {
|
||||
$r = array_merge($r, $sub_r);
|
||||
}
|
||||
return ($v == $sub_v) ? array(0, $v) : array($r, $sub_v);
|
||||
}
|
||||
|
||||
/* +8 */
|
||||
|
||||
function xGroupClause($v) {
|
||||
if ($sub_r = $this->x('GROUP BY\s+', $v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$r = array();
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
|
||||
$r[] = $sub_r;
|
||||
$proceed = 1;
|
||||
if ($sub_r = $this->x('\,', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
if (count($r)) {
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
else {
|
||||
$this->addError('No columns specified in GROUP BY clause.');
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
}
|
||||
116
arc/parsers/ARC2_SPARQLXMLResultParser.php
Normal file
116
arc/parsers/ARC2_SPARQLXMLResultParser.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 SPARQL Result XML Parser
|
||||
author: Benjamin Nowack
|
||||
version: 2008-08-28 (Addition: Support for "inserted" and "deleted")
|
||||
*/
|
||||
|
||||
ARC2::inc('LegacyXMLParser');
|
||||
|
||||
class ARC2_SPARQLXMLResultParser extends ARC2_LegacyXMLParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_SPARQLXMLResultParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* reader */
|
||||
parent::__init();
|
||||
$this->srx = 'http://www.w3.org/2005/sparql-results#';
|
||||
$this->nsp[$this->srx] = 'srx';
|
||||
$this->allowCDataNodes = 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function done() {
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getVariables() {
|
||||
$r = array();
|
||||
foreach ($this->nodes as $node) {
|
||||
if ($node['tag'] == $this->srx . 'variable') {
|
||||
$r[] = $node['a']['name'];
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getRows() {
|
||||
$r = array();
|
||||
$index = $this->getNodeIndex();
|
||||
foreach ($this->nodes as $node) {
|
||||
if ($node['tag'] == $this->srx . 'result') {
|
||||
$row = array();
|
||||
$row_id = $node['id'];
|
||||
$bindings = isset($index[$row_id])? $index[$row_id] : array();
|
||||
foreach ($bindings as $binding) {
|
||||
$row = array_merge($row, $this->getBinding($binding));
|
||||
}
|
||||
if ($row) {
|
||||
$r[] = $row;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getBinding($node) {
|
||||
$r = array();
|
||||
$index = $this->getNodeIndex();
|
||||
$var = $node['a']['name'];
|
||||
$term = $index[$node['id']][0];
|
||||
$r[$var . ' type'] = preg_replace('/^uri$/', 'uri', substr($term['tag'], strlen($this->srx)));
|
||||
$r[$var] = ($r[$var . ' type'] == 'bnode') ? '_:' . $term['cdata'] : $term['cdata'];
|
||||
if (isset($term['a']['datatype'])) {
|
||||
$r[$var . ' datatype'] = $term['a']['datatype'];
|
||||
}
|
||||
elseif (isset($term['a'][$this->xml . 'lang'])) {
|
||||
$r[$var . ' lang'] = $term['a'][$this->xml . 'lang'];
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getBooleanInsertedDeleted() {
|
||||
foreach ($this->nodes as $node) {
|
||||
if ($node['tag'] == $this->srx . 'boolean') {
|
||||
return ($node['cdata'] == 'true') ? array('boolean' => true) : array('boolean' => false);
|
||||
}
|
||||
elseif ($node['tag'] == $this->srx . 'inserted') {
|
||||
return array('inserted' => $node['cdata']);
|
||||
}
|
||||
elseif ($node['tag'] == $this->srx . 'deleted') {
|
||||
return array('deleted' => $node['cdata']);
|
||||
}
|
||||
elseif ($node['tag'] == $this->srx . 'results') {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getStructure() {
|
||||
$r = array('variables' => $this->getVariables(), 'rows' => $this->getRows());
|
||||
/* boolean|inserted|deleted */
|
||||
if ($sub_r = $this->getBooleanInsertedDeleted()) {
|
||||
foreach ($sub_r as $k => $v) {
|
||||
$r[$k] = $v;
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
|
||||
}
|
||||
167
arc/parsers/ARC2_SPOGParser.php
Normal file
167
arc/parsers/ARC2_SPOGParser.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 SPOG Parser (streaming)
|
||||
author: Benjamin Nowack
|
||||
version: 2008-07-02
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFParser');
|
||||
|
||||
class ARC2_SPOGParser extends ARC2_RDFParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_SPOGParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* reader */
|
||||
parent::__init();
|
||||
$this->encoding = $this->v('encoding', false, $this->a);
|
||||
$this->xml = 'http://www.w3.org/XML/1998/namespace';
|
||||
$this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
$this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf');
|
||||
$this->target_encoding = '';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function parse($path, $data = '') {
|
||||
$this->state = 0;
|
||||
/* reader */
|
||||
if (!$this->v('reader')) {
|
||||
ARC2::inc('Reader');
|
||||
$this->reader = & new ARC2_Reader($this->a, $this);
|
||||
}
|
||||
$this->reader->setAcceptHeader('Accept: sparql-results+xml; q=0.9, */*; q=0.1');
|
||||
$this->reader->activate($path, $data);
|
||||
$this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
|
||||
/* xml parser */
|
||||
$this->initXMLParser();
|
||||
/* parse */
|
||||
$first = true;
|
||||
while ($d = $this->reader->readStream()) {
|
||||
if (!xml_parse($this->xml_parser, $d, false)) {
|
||||
$error_str = xml_error_string(xml_get_error_code($this->xml_parser));
|
||||
$line = xml_get_current_line_number($this->xml_parser);
|
||||
$this->tmp_error = 'XML error: "' . $error_str . '" at line ' . $line . ' (parsing as ' . $this->getEncoding() . ')';
|
||||
return $this->addError($this->tmp_error);
|
||||
}
|
||||
}
|
||||
$this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
|
||||
xml_parser_free($this->xml_parser);
|
||||
$this->reader->closeStream();
|
||||
unset($this->reader);
|
||||
return $this->done();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function initXMLParser() {
|
||||
if (!isset($this->xml_parser)) {
|
||||
$enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
|
||||
$parser = xml_parser_create($enc);
|
||||
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
|
||||
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
|
||||
xml_set_element_handler($parser, 'open', 'close');
|
||||
xml_set_character_data_handler($parser, 'cdata');
|
||||
xml_set_start_namespace_decl_handler($parser, 'nsDecl');
|
||||
xml_set_object($parser, $this);
|
||||
$this->xml_parser =& $parser;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getEncoding($src = 'config') {
|
||||
return 'UTF-8';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTriples() {
|
||||
return $this->v('triples', array());
|
||||
}
|
||||
|
||||
function countTriples() {
|
||||
return $this->t_count;
|
||||
}
|
||||
|
||||
function addT($s = '', $p = '', $o = '', $s_type = '', $o_type = '', $o_dt = '', $o_lang = '', $g = '') {
|
||||
if (!($s && $p && $o)) return 0;
|
||||
//echo "-----\nadding $s / $p / $o\n-----\n";
|
||||
$t = array('s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang, 'g' => $g);
|
||||
if ($this->skip_dupes) {
|
||||
$h = md5(serialize($t));
|
||||
if (!isset($this->added_triples[$h])) {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
$this->added_triples[$h] = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function open($p, $t, $a) {
|
||||
$this->state = $t;
|
||||
if ($t == 'result') {
|
||||
$this->t = array();
|
||||
}
|
||||
elseif ($t == 'binding') {
|
||||
$this->binding = $a['name'];
|
||||
$this->t[$this->binding] = '';
|
||||
}
|
||||
elseif ($t == 'literal') {
|
||||
$this->t[$this->binding . '_dt'] = $this->v('datatype', '', $a);
|
||||
$this->t[$this->binding . '_lang'] = $this->v('xml:lang', '', $a);
|
||||
$this->t[$this->binding . '_type'] = 'literal';
|
||||
}
|
||||
elseif ($t == 'uri') {
|
||||
$this->t[$this->binding . '_type'] = 'uri';
|
||||
}
|
||||
elseif ($t == 'bnode') {
|
||||
$this->t[$this->binding . '_type'] = 'bnode';
|
||||
$this->t[$this->binding] = '_:';
|
||||
}
|
||||
}
|
||||
|
||||
function close($p, $t) {
|
||||
$this->prev_state = $this->state;
|
||||
$this->state = '';
|
||||
if ($t == 'result') {
|
||||
$this->addT(
|
||||
$this->v('s', '', $this->t),
|
||||
$this->v('p', '', $this->t),
|
||||
$this->v('o', '', $this->t),
|
||||
$this->v('s_type', '', $this->t),
|
||||
$this->v('o_type', '', $this->t),
|
||||
$this->v('o_dt', '', $this->t),
|
||||
$this->v('o_lang', '', $this->t),
|
||||
$this->v('g', '', $this->t)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function cData($p, $d) {
|
||||
if (in_array($this->state, array('uri', 'bnode', 'literal'))) {
|
||||
$this->t[$this->binding] .= $d;
|
||||
}
|
||||
}
|
||||
|
||||
function nsDecl($p, $prf, $uri) {
|
||||
$this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
351
arc/parsers/ARC2_SemHTMLParser.php
Normal file
351
arc/parsers/ARC2_SemHTMLParser.php
Normal file
@@ -0,0 +1,351 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 RDF/XML Parser
|
||||
author: Benjamin Nowack
|
||||
version: 2009-02-09 (Addition: Support for RDFa detection via typeof/property/about)
|
||||
*/
|
||||
|
||||
ARC2::inc('LegacyXMLParser');
|
||||
|
||||
class ARC2_SemHTMLParser extends ARC2_LegacyXMLParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_SemHTMLParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* reader */
|
||||
parent::__init();
|
||||
$this->default_sem_html_formats = 'dc openid erdf rdfa posh-rdf microformats';
|
||||
$this->triples = array();
|
||||
$this->target_encoding = '';
|
||||
$this->t_count = 0;
|
||||
$this->added_triples = array();
|
||||
$this->skip_dupes = false;
|
||||
$this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
|
||||
$this->bnode_id = 0;
|
||||
$this->auto_extract = $this->v('auto_extract', 1, $this->a);
|
||||
$this->extracted_formats = array();
|
||||
$this->cache = array();
|
||||
$this->detected_formats = array();
|
||||
$this->keep_cdata_ws = $this->v('keep_cdata_whitespace', 0, $this->a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function x($re, $v, $options = 'si', $keep_ws = 0) {
|
||||
list($ws, $v) = preg_match('/^(\s*)(.*)$/s', $v, $m) ? array($m[1], $m[2]) : array('', $v);
|
||||
if (preg_match("/^" . $re . "(.*)$/" . $options, $v, $m)) {
|
||||
if ($keep_ws) $m[1] = $ws . $m[1];
|
||||
return $m;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function camelCase($v) {
|
||||
$r = ucfirst($v);
|
||||
while (preg_match('/^(.*)[\-\_ ](.*)$/', $r, $m)) {
|
||||
$r = $m[1] . ucfirst($m[2]);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function setReader(&$reader) {
|
||||
$this->reader =& $reader;
|
||||
}
|
||||
|
||||
function createBnodeID(){
|
||||
$this->bnode_id++;
|
||||
return '_:' . $this->bnode_prefix . $this->bnode_id;
|
||||
}
|
||||
|
||||
function addT($t) {
|
||||
if (function_exists('html_entity_decode')) {
|
||||
$t['o'] = html_entity_decode($t['o']);
|
||||
}
|
||||
if ($this->skip_dupes) {
|
||||
$h = md5(serialize($t));
|
||||
if (!isset($this->added_triples[$h])) {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
$this->added_triples[$h] = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
}
|
||||
}
|
||||
|
||||
function getTriples() {
|
||||
return $this->v('triples', array());
|
||||
}
|
||||
|
||||
function countTriples() {
|
||||
return $this->t_count;
|
||||
}
|
||||
|
||||
function getSimpleIndex($flatten_objects = 1, $vals = '') {
|
||||
return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function parse($path, $data = '') {
|
||||
$this->nodes = array();
|
||||
$this->node_count = 0;
|
||||
$this->level = 0;
|
||||
/* reader */
|
||||
if (!$this->v('reader')) {
|
||||
ARC2::inc('Reader');
|
||||
$this->reader = & new ARC2_Reader($this->a, $this);
|
||||
}
|
||||
$this->reader->setAcceptHeader('Accept: text/html, application/xhtml, */*; q=0.9');
|
||||
$this->reader->activate($path, $data);
|
||||
$this->target_encoding = $this->reader->getEncoding(false);
|
||||
$this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
|
||||
$this->base = $this->x_base;
|
||||
$this->doc_url = $this->reader->base;
|
||||
/* parse */
|
||||
$rest = '';
|
||||
$this->cur_tag = '';
|
||||
while ($d = $this->reader->readStream(1)) {
|
||||
$rest = $this->processData($rest . $d);
|
||||
}
|
||||
$this->reader->closeStream();
|
||||
unset($this->reader);
|
||||
return $this->done();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getEncoding() {
|
||||
return $this->target_encoding;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function done() {
|
||||
if ($this->auto_extract) {
|
||||
$this->extractRDF();
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processData($v) {
|
||||
$sub_v = $v;
|
||||
do {
|
||||
$proceed = 1;
|
||||
if ((list($sub_r, $sub_v) = $this->xComment($sub_v)) && $sub_r) {
|
||||
$this->open(0, 'comment', array('value' => $sub_r));
|
||||
$this->close(0, 'comment');
|
||||
continue;
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xDoctype($sub_v)) && $sub_r) {
|
||||
$this->open(0, 'doctype', array('value' => $sub_r));
|
||||
$this->close(0, 'doctype');
|
||||
/* RDFa detection */
|
||||
if (preg_match('/rdfa /i', $sub_r)) $this->detected_formats['rdfa'] = 1;
|
||||
continue;
|
||||
}
|
||||
if ($this->level && ((list($sub_r, $sub_v) = $this->xWS($sub_v)) && $sub_r)) {
|
||||
$this->cData(0, $sub_r);
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xOpen($sub_v)) && $sub_r) {
|
||||
$this->open(0, $sub_r['tag'], $sub_r['a']);
|
||||
$this->cur_tag = $sub_r['tag'];
|
||||
if ($sub_r['empty']) {
|
||||
$this->close(0, $sub_r['tag'], 1);
|
||||
$this->cur_tag = '';
|
||||
}
|
||||
/* eRDF detection */
|
||||
if (!isset($this->detected_formats['erdf']) && isset($sub_r['a']['profile m']) && in_array('http://purl.org/NET/erdf/profile', $sub_r['a']['profile m'])) $this->detected_formats['erdf'] = 1;
|
||||
/* poshRDF detection */
|
||||
if (!isset($this->detected_formats['posh-rdf']) && isset($sub_r['a']['class m']) && in_array('rdf-p', $sub_r['a']['class m'])) $this->detected_formats['posh-rdf'] = 1;
|
||||
/* RDFa detection */
|
||||
if (!isset($this->detected_formats['rdfa']) && ($this->cur_tag == 'html') && isset($sub_r['a']['version m']) && in_array('XHTML+RDFa', $sub_r['a']['version m'])) $this->detected_formats['rdfa'] = 1;
|
||||
if (!isset($this->detected_formats['rdfa']) && isset($sub_r['a']['xmlns']) && $sub_r['a']['xmlns'] && $this->isRDFNSDecl($sub_r['a']['xmlns'])) $this->detected_formats['rdfa'] = 1;
|
||||
if (!isset($this->detected_formats['rdfa']) && array_intersect(array('about', 'typeof', 'property'), array_keys($sub_r['a']))) $this->detected_formats['rdfa'] = 1;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xClose($sub_v)) && $sub_r) {
|
||||
if (preg_match('/^(area|base|br|col|frame|hr|input|img|link|xmeta|param)$/', $sub_r['tag'])) {
|
||||
/* already implicitly closed */
|
||||
}
|
||||
else {
|
||||
$this->close(0, $sub_r['tag']);
|
||||
$this->cur_tag = '';
|
||||
}
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xCData($sub_v)) && $sub_r) {
|
||||
$this->cData(0, $sub_r);
|
||||
}
|
||||
else {
|
||||
$proceed = 0;
|
||||
}
|
||||
} while ($proceed);
|
||||
return $sub_v;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function isRDFNSDecl($ns) {
|
||||
foreach ($ns as $k => $v) {
|
||||
if ($k) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function xComment($v) {
|
||||
if ($r = $this->x('\<\!\-\-', $v)) {
|
||||
if ($sub_r = $this->x('(.*)\-\-\>', $r[1], 'Us')) {
|
||||
return array($sub_r[1], $sub_r[2]);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
function xDoctype($v) {
|
||||
if ($r = $this->x('\<\!DOCTYPE', $v)) {
|
||||
if ($sub_r = $this->x('([^\>]+)\>', $r[1])) {
|
||||
return array($sub_r[1], $sub_r[2]);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
function xWS($v) {
|
||||
if ($r = ARC2::x('(\s+)', $v)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function xOpen($v) {
|
||||
if ($r = $this->x('\<([^\s\/\>]+)([^\>]*)\>', $v)) {
|
||||
list($sub_r, $sub_v) = $this->xAttributes($r[2]);
|
||||
return array(array('tag' => strtolower($r[1]), 'a' => $sub_r, 'empty' => $this->isEmpty($r[1], $r[2])), $r[3]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function xAttributes($v) {
|
||||
$r = array();
|
||||
while ((list($sub_r, $v) = $this->xAttribute($v)) && $sub_r) {
|
||||
if ($sub_sub_r = $this->x('xmlns\:?(.*)', $sub_r['k'])) {
|
||||
$this->nsDecl(0, $sub_sub_r[1], $sub_r['value']);
|
||||
$r['xmlns'][$sub_sub_r[1]] = $sub_r['value'];
|
||||
}
|
||||
else {
|
||||
$r[$sub_r['k']] = $sub_r['value'];
|
||||
$r[$sub_r['k'] . ' m'] = $sub_r['values'];
|
||||
}
|
||||
}
|
||||
return array($r, $v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function xAttribute($v) {
|
||||
if ($r = $this->x('([^\s\=]+)\s*(\=)?\s*([\'\"]?)', $v)) {
|
||||
if (!$r[2]) {/* no '=' */
|
||||
if ($r[1] == '/') {
|
||||
return array(0, $r[4]);
|
||||
}
|
||||
return array(array('k' => $r[1], 'value' => 1, 'values' => array(1)), $r[4]);
|
||||
}
|
||||
if (!$r[3]) {/* no quots */
|
||||
if ($sub_r = $this->x('([^\s]+)', $r[4])) {
|
||||
return array(array('k' => $r[1], 'value' => $sub_r[1], 'values' => array($sub_r[1])), $sub_r[2]);
|
||||
}
|
||||
return array(array('k' => $r[1], 'value' => '', 'values' => array()), $r[4]);
|
||||
}
|
||||
$val = '';
|
||||
$multi = 0;
|
||||
$sub_v = $r[4];
|
||||
while ($sub_v && (!$sub_r = $this->x('(\x5c\\' .$r[3]. '|\\' .$r[3]. ')', $sub_v))) {
|
||||
$val .= substr($sub_v, 0, 1);
|
||||
$sub_v = substr($sub_v, 1);
|
||||
}
|
||||
$sub_v = $sub_v ? $sub_r[2] : $sub_v;
|
||||
$vals = split(' ', $val);
|
||||
return array(array('k' => $r[1], 'value' => $val, 'values' => $vals), $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function isEmpty($t, $v) {
|
||||
if (preg_match('/^(area|base|br|col|frame|hr|input|img|link|xmeta|param)$/', $t)) {
|
||||
return 1;
|
||||
}
|
||||
if (preg_match('/\/$/', $v)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function xClose($v) {
|
||||
if ($r = $this->x('\<\/([^\s\>]+)\>', $v)) {
|
||||
return array(array('tag' => strtolower($r[1])), $r[2]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function xCData($v) {
|
||||
if (preg_match('/(script|style)/i', $this->cur_tag)) {
|
||||
if ($r = $this->x('(.+)(\<\/' . $this->cur_tag . '\>)', $v, 'Uis')) {
|
||||
return array($r[1], $r[2] . $r[3]);
|
||||
}
|
||||
}
|
||||
elseif ($r = $this->x('([^\<]+)', $v, 'si', $this->keep_cdata_ws)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractRDF($formats = '') {
|
||||
$this->node_index = $this->getNodeIndex();
|
||||
$formats = !$formats ? $this->v1('sem_html_formats', $this->default_sem_html_formats, $this->a) : $formats;
|
||||
$formats = split(' ', $formats);
|
||||
foreach ($formats as $format) {
|
||||
if (!in_array($format, $this->extracted_formats)) {
|
||||
$comp = $this->camelCase($format) . 'Extractor';
|
||||
if (ARC2::inc($comp)) {
|
||||
$cls = 'ARC2_' . $comp;
|
||||
$e = new $cls($this->a, $this);
|
||||
$e->extractRDF();
|
||||
}
|
||||
$this->extracted_formats[] = $format;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getNode($id) {
|
||||
return isset($this->nodes[$id]) ? $this->nodes[$id] : 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
885
arc/parsers/ARC2_TurtleParser.php
Normal file
885
arc/parsers/ARC2_TurtleParser.php
Normal file
@@ -0,0 +1,885 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 SPARQL-enhanced Turtle Parser
|
||||
*
|
||||
* @author Benjamin Nowack
|
||||
* @license <http://arc.semsol.org/license>
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-11-16
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFParser');
|
||||
|
||||
class ARC2_TurtleParser extends ARC2_RDFParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_TurtleParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* reader */
|
||||
parent::__init();
|
||||
$this->state = 0;
|
||||
$this->xml = 'http://www.w3.org/XML/1998/namespace';
|
||||
$this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
$this->xsd = 'http://www.w3.org/2001/XMLSchema#';
|
||||
$this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf', $this->xsd => 'xsd');
|
||||
$this->unparsed_code = '';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function x($re, $v, $options = 'si') {
|
||||
$v = preg_replace('/^[\xA0\xC2]+/', ' ', $v);
|
||||
while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $v, $m)) {/* comment removal */
|
||||
$v = $m[2];
|
||||
}
|
||||
return ARC2::x($re, $v, $options);
|
||||
//$this->unparsed_code = ($sub_r && count($sub_r)) ? $sub_r[count($sub_r) - 1] : '';
|
||||
}
|
||||
|
||||
function createBnodeID(){
|
||||
$this->bnode_id++;
|
||||
return '_:' . $this->bnode_prefix . $this->bnode_id;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function addT($t) {
|
||||
if ($this->skip_dupes) {
|
||||
$h = md5(serialize($t));
|
||||
if (!isset($this->added_triples[$h])) {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
$this->added_triples[$h] = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->triples[$this->t_count] = $t;
|
||||
$this->t_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTriples() {
|
||||
return $this->v('triples', array());
|
||||
}
|
||||
|
||||
function countTriples() {
|
||||
return $this->t_count;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getUnparsedCode() {
|
||||
return $this->v('unparsed_code', '');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function setDefaultPrefixes() {
|
||||
$this->prefixes = array(
|
||||
'rdf:' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
||||
'rdfs:' => 'http://www.w3.org/2000/01/rdf-schema#',
|
||||
'owl:' => 'http://www.w3.org/2002/07/owl#',
|
||||
'xsd:' => 'http://www.w3.org/2001/XMLSchema#',
|
||||
);
|
||||
if ($ns = $this->v('ns', array(), $this->a)) {
|
||||
foreach ($ns as $p => $u) $this->prefixes[$p . ':'] = $u;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function parse($path, $data = '', $iso_fallback = false) {
|
||||
$this->setDefaultPrefixes();
|
||||
/* reader */
|
||||
if (!$this->v('reader')) {
|
||||
ARC2::inc('Reader');
|
||||
$this->reader = & new ARC2_Reader($this->a, $this);
|
||||
}
|
||||
$this->reader->setAcceptHeader('Accept: application/x-turtle; q=0.9, */*; q=0.1');
|
||||
$this->reader->activate($path, $data);
|
||||
$this->base = $this->v1('base', $this->reader->base, $this->a);
|
||||
$this->r = array('vars' => array());
|
||||
/* parse */
|
||||
$buffer = '';
|
||||
$more_triples = array();
|
||||
$sub_v = '';
|
||||
$sub_v2 = '';
|
||||
$loops = 0;
|
||||
$prologue_done = 0;
|
||||
while ($d = $this->reader->readStream(0)) {
|
||||
$buffer .= $d;
|
||||
$sub_v = $buffer;
|
||||
do {
|
||||
$proceed = 0;
|
||||
if (!$prologue_done) {
|
||||
$proceed = 1;
|
||||
if ((list($sub_r, $sub_v) = $this->xPrologue($sub_v)) && $sub_r) {
|
||||
$loops = 0;
|
||||
$sub_v .= $this->reader->readStream(0, 128);
|
||||
/* we might have missed the final DOT in the previous prologue loop */
|
||||
if ($sub_r = $this->x('\.', $sub_v)) $sub_v = $sub_r[1];
|
||||
if ($this->x("\@?(base|prefix)", $sub_v)) {/* more prologue to come, use outer loop */
|
||||
$proceed = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$prologue_done = 1;
|
||||
}
|
||||
}
|
||||
if ($prologue_done && (list($sub_r, $sub_v, $more_triples, $sub_v2) = $this->xTriplesBlock($sub_v)) && is_array($sub_r)) {
|
||||
$proceed = 1;
|
||||
$loops = 0;
|
||||
foreach ($sub_r as $t) {
|
||||
$this->addT($t);
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
$loops++;
|
||||
$buffer = $sub_v;
|
||||
if ($loops > 100) {/* most probably a parser or code bug, might also be a huge object value, though */
|
||||
$this->addError('too many loops: ' . $loops . '. Could not parse "' . substr($buffer, 0, 200) . '..."');
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach ($more_triples as $t) {
|
||||
$this->addT($t);
|
||||
}
|
||||
$sub_v = count($more_triples) ? $sub_v2 : $sub_v;
|
||||
$buffer = $sub_v;
|
||||
$this->unparsed_code = $buffer;
|
||||
$this->reader->closeStream();
|
||||
unset($this->reader);
|
||||
/* remove trailing comments */
|
||||
while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $this->unparsed_code, $m)) $this->unparsed_code = $m[2];
|
||||
if ($this->unparsed_code && !$this->getErrors()) {
|
||||
$rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
|
||||
if (trim($rest)) $this->addError('Could not parse "' . $rest . '"');
|
||||
}
|
||||
return $this->done();
|
||||
}
|
||||
|
||||
function xPrologue($v) {
|
||||
$r = 0;
|
||||
if (!$this->t_count) {
|
||||
if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
|
||||
$this->base = $sub_r;
|
||||
$r = 1;
|
||||
}
|
||||
while ((list($sub_r, $v) = $this->xPrefixDecl($v)) && $sub_r) {
|
||||
$this->prefixes[$sub_r['prefix']] = $sub_r['uri'];
|
||||
$r = 1;
|
||||
}
|
||||
}
|
||||
return array($r, $v);
|
||||
}
|
||||
|
||||
/* 3 */
|
||||
|
||||
function xBaseDecl($v) {
|
||||
if ($r = $this->x("\@?base\s+", $v)) {
|
||||
if ((list($r, $sub_v) = $this->xIRI_REF($r[1])) && $r) {
|
||||
if ($sub_r = $this->x('\.', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
}
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 4 */
|
||||
|
||||
function xPrefixDecl($v) {
|
||||
if ($r = $this->x("\@?prefix\s+", $v)) {
|
||||
if ((list($r, $sub_v) = $this->xPNAME_NS($r[1])) && $r) {
|
||||
$prefix = $r;
|
||||
if((list($r, $sub_v) = $this->xIRI_REF($sub_v)) && $r) {
|
||||
$uri = $this->calcURI($r, $this->base);
|
||||
if ($sub_r = $this->x('\.', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
}
|
||||
return array(array('prefix' => $prefix, 'uri_ref' => $r, 'uri' => $uri), $sub_v);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 21.., 32.. */
|
||||
|
||||
function xTriplesBlock($v) {
|
||||
$pre_r = array();
|
||||
$r = array();
|
||||
$state = 1;
|
||||
$sub_v = $v;
|
||||
$buffer = $sub_v;
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ($state == 1) {/* expecting subject */
|
||||
$t = array('type' => 'triple', 's' => '', 'p' => '', 'o' => '', 's_type' => '', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => '');
|
||||
if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
|
||||
$t['s'] = $sub_r['value'];
|
||||
$t['s_type'] = $sub_r['type'];
|
||||
$state = 2;
|
||||
$proceed = 1;
|
||||
if ($sub_r = $this->x('(\}|\.)', $sub_v)) {
|
||||
if ($t['s_type'] == 'placeholder') {
|
||||
$state = 4;
|
||||
}
|
||||
else {
|
||||
$this->addError('"' . $sub_r[1]. '" after subject found.');
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
|
||||
$t['s'] = $sub_r['id'];
|
||||
$t['s_type'] = $sub_r['type'];
|
||||
$pre_r = array_merge($pre_r, $sub_r['triples']);
|
||||
$state = 2;
|
||||
$proceed = 1;
|
||||
if ($sub_r = $this->x('\.', $sub_v)) {
|
||||
$this->addError('DOT after subject found.');
|
||||
}
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
|
||||
$t['s'] = $sub_r['id'];
|
||||
$t['s_type'] = $sub_r['type'];
|
||||
$pre_r = array_merge($pre_r, $sub_r['triples']);
|
||||
$state = 2;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ($sub_r = $this->x('\.', $sub_v)) {
|
||||
$this->addError('Subject expected, DOT found.' . $sub_v);
|
||||
}
|
||||
}
|
||||
if ($state == 2) {/* expecting predicate */
|
||||
if ($sub_r = $this->x('a\s+', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$t['p'] = $this->rdf . 'type';
|
||||
$t['p_type'] = 'uri';
|
||||
$state = 3;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
|
||||
if ($sub_r['type'] == 'bnode') {
|
||||
$this->addError('Blank node used as triple predicate');
|
||||
}
|
||||
$t['p'] = $sub_r['value'];
|
||||
$t['p_type'] = $sub_r['type'];
|
||||
$state = 3;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ($sub_r = $this->x('\.', $sub_v)) {
|
||||
$state = 4;
|
||||
}
|
||||
elseif ($sub_r = $this->x('\}', $sub_v)) {
|
||||
$buffer = $sub_v;
|
||||
$r = array_merge($r, $pre_r);
|
||||
$pre_r = array();
|
||||
$proceed = 0;
|
||||
}
|
||||
}
|
||||
if ($state == 3) {/* expecting object */
|
||||
if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
|
||||
$t['o'] = $sub_r['value'];
|
||||
$t['o_type'] = $sub_r['type'];
|
||||
$t['o_lang'] = $this->v('lang', '', $sub_r);
|
||||
$t['o_datatype'] = $this->v('datatype', '', $sub_r);
|
||||
$pre_r[] = $t;
|
||||
$state = 4;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
|
||||
$t['o'] = $sub_r['id'];
|
||||
$t['o_type'] = $sub_r['type'];
|
||||
$pre_r = array_merge($pre_r, array($t), $sub_r['triples']);
|
||||
$state = 4;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
|
||||
$t['o'] = $sub_r['id'];
|
||||
$t['o_type'] = $sub_r['type'];
|
||||
$pre_r = array_merge($pre_r, array($t), $sub_r['triples']);
|
||||
$state = 4;
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
if ($state == 4) {/* expecting . or ; or , or } */
|
||||
if ($sub_r = $this->x('\.', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$buffer = $sub_v;
|
||||
$r = array_merge($r, $pre_r);
|
||||
$pre_r = array();
|
||||
$state = 1;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ($sub_r = $this->x('\;', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$state = 2;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ($sub_r = $this->x('\,', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$state = 3;
|
||||
$proceed = 1;
|
||||
if ($sub_r = $this->x('\}', $sub_v)) {
|
||||
$this->addError('Object expected, } found.');
|
||||
}
|
||||
}
|
||||
if ($sub_r = $this->x('(\}|\{|OPTIONAL|FILTER|GRAPH)', $sub_v)) {
|
||||
$buffer = $sub_v;
|
||||
$r = array_merge($r, $pre_r);
|
||||
$pre_r = array();
|
||||
$proceed = 0;
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
return count($r) ? array($r, $buffer, $pre_r, $sub_v) : array(0, $buffer, $pre_r, $sub_v);
|
||||
}
|
||||
|
||||
/* 39.. */
|
||||
|
||||
function xBlankNodePropertyList($v) {
|
||||
if ($sub_r = $this->x('\[', $v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$s = $this->createBnodeID();
|
||||
$r = array('id' => $s, 'type' => 'bnode', 'triples' => array());
|
||||
$t = array('type' => 'triple', 's' => $s, 'p' => '', 'o' => '', 's_type' => 'bnode', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => '');
|
||||
$state = 2;
|
||||
$closed = 0;
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ($state == 2) {/* expecting predicate */
|
||||
if ($sub_r = $this->x('a\s+', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$t['p'] = $this->rdf . 'type';
|
||||
$t['p_type'] = 'uri';
|
||||
$state = 3;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
|
||||
$t['p'] = $sub_r['value'];
|
||||
$t['p_type'] = $sub_r['type'];
|
||||
$state = 3;
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
if ($state == 3) {/* expecting object */
|
||||
if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
|
||||
$t['o'] = $sub_r['value'];
|
||||
$t['o_type'] = $sub_r['type'];
|
||||
$t['o_lang'] = $this->v('lang', '', $sub_r);
|
||||
$t['o_datatype'] = $this->v('datatype', '', $sub_r);
|
||||
$r['triples'][] = $t;
|
||||
$state = 4;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
|
||||
$t['o'] = $sub_r['id'];
|
||||
$t['o_type'] = $sub_r['type'];
|
||||
$r['triples'] = array_merge($r['triples'], array($t), $sub_r['triples']);
|
||||
$state = 4;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
|
||||
$t['o'] = $sub_r['id'];
|
||||
$t['o_type'] = $sub_r['type'];
|
||||
$r['triples'] = array_merge($r['triples'], array($t), $sub_r['triples']);
|
||||
$state = 4;
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
if ($state == 4) {/* expecting . or ; or , or ] */
|
||||
if ($sub_r = $this->x('\.', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$state = 1;
|
||||
$proceed = 1;
|
||||
}
|
||||
if ($sub_r = $this->x('\;', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$state = 2;
|
||||
$proceed = 1;
|
||||
}
|
||||
if ($sub_r = $this->x('\,', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$state = 3;
|
||||
$proceed = 1;
|
||||
}
|
||||
if ($sub_r = $this->x('\]', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$proceed = 0;
|
||||
$closed = 1;
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
if ($closed) {
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 40.. */
|
||||
|
||||
function xCollection($v) {
|
||||
if ($sub_r = $this->x('\(', $v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$s = $this->createBnodeID();
|
||||
$r = array('id' => $s, 'type' => 'bnode', 'triples' => array());
|
||||
$closed = 0;
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
|
||||
$r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['value'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => $this->v('lang', '', $sub_r), 'o_datatype' => $this->v('datatype', '', $sub_r));
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
|
||||
$r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => '');
|
||||
$r['triples'] = array_merge($r['triples'], $sub_r['triples']);
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
|
||||
$r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => '');
|
||||
$r['triples'] = array_merge($r['triples'], $sub_r['triples']);
|
||||
$proceed = 1;
|
||||
}
|
||||
if ($proceed) {
|
||||
if ($sub_r = $this->x('\)', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
$r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'rest', 'o' => $this->rdf . 'nil', 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'uri', 'o_lang' => '', 'o_datatype' => '');
|
||||
$closed = 1;
|
||||
$proceed = 0;
|
||||
}
|
||||
else {
|
||||
$next_s = $this->createBnodeID();
|
||||
$r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'rest', 'o' => $next_s, 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'bnode', 'o_lang' => '', 'o_datatype' => '');
|
||||
$s = $next_s;
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
if ($closed) {
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
}
|
||||
return array (0, $v);
|
||||
}
|
||||
|
||||
/* 42 */
|
||||
|
||||
function xVarOrTerm($v) {
|
||||
if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xGraphTerm($v)) && $sub_r) {
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 44, 74.., 75.. */
|
||||
|
||||
function xVar($v) {
|
||||
if ($r = $this->x('(\?|\$)([^\s]+)', $v)) {
|
||||
if ((list($sub_r, $sub_v) = $this->xVARNAME($r[2])) && $sub_r) {
|
||||
if (!in_array($sub_r, $this->r['vars'])) {
|
||||
$this->r['vars'][] = $sub_r;
|
||||
}
|
||||
return array(array('value' => $sub_r, 'type' => 'var'), $sub_v . $r[3]);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 45 */
|
||||
|
||||
function xGraphTerm($v) {
|
||||
foreach (array(
|
||||
'IRIref' => 'uri',
|
||||
'RDFLiteral' => 'literal',
|
||||
'NumericLiteral' => 'literal',
|
||||
'BooleanLiteral' => 'literal',
|
||||
'BlankNode' => 'bnode',
|
||||
'NIL' => 'uri',
|
||||
'Placeholder' => 'placeholder'
|
||||
) as $term => $type) {
|
||||
$m = 'x' . $term;
|
||||
if ((list($sub_r, $sub_v) = $this->$m($v)) && $sub_r) {
|
||||
if (!is_array($sub_r)) {
|
||||
$sub_r = array('value' => $sub_r);
|
||||
}
|
||||
$sub_r['type'] = $this->v1('type', $type, $sub_r);
|
||||
return array($sub_r, $sub_v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 60 */
|
||||
|
||||
function xRDFLiteral($v) {
|
||||
if ((list($sub_r, $sub_v) = $this->xString($v)) && $sub_r) {
|
||||
$sub_r['value'] = $this->unescapeNtripleUTF($sub_r['value']);
|
||||
$r = $sub_r;
|
||||
if ((list($sub_r, $sub_v) = $this->xLANGTAG($sub_v)) && $sub_r) {
|
||||
$r['lang'] = $sub_r;
|
||||
}
|
||||
elseif (!$this->x('\s', $sub_v) && ($sub_r = $this->x('\^\^', $sub_v)) && (list($sub_r, $sub_v) = $this->xIRIref($sub_r[1])) && $sub_r[1]) {
|
||||
$r['datatype'] = $sub_r;
|
||||
}
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 61.., 62.., 63.., 64.. */
|
||||
|
||||
function xNumericLiteral($v) {
|
||||
$sub_r = $this->x('(\-|\+)?', $v);
|
||||
$prefix = $sub_r[1];
|
||||
$sub_v = $sub_r[2];
|
||||
foreach (array('DOUBLE' => 'double', 'DECIMAL' => 'decimal', 'INTEGER' => 'integer') as $type => $xsd) {
|
||||
$m = 'x' . $type;
|
||||
if ((list($sub_r, $sub_v) = $this->$m($sub_v)) && ($sub_r !== false)) {
|
||||
$r = array('value' => $prefix . $sub_r, 'type' => 'literal', 'datatype' => $this->xsd . $xsd);
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 65.. */
|
||||
|
||||
function xBooleanLiteral($v) {
|
||||
if ($r = $this->x('(true|false)', $v)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 66.., 87.., 88.., 89.., 90.., 91.. */
|
||||
|
||||
function xString($v) {/* largely simplified, may need some tweaks in following revisions */
|
||||
$sub_v = $v;
|
||||
if (!preg_match('/^\s*([\']{3}|\'|[\"]{3}|\")(.*)$/s', $sub_v, $m)) return array(0, $v);
|
||||
$delim = $m[1];
|
||||
$rest = $m[2];
|
||||
$sub_types = array("'''" => 'literal_long1', '"""' => 'literal_long2', "'" => 'literal1', '"' => 'literal2');
|
||||
$sub_type = $sub_types[$delim];
|
||||
$pos = 0;
|
||||
$r = false;
|
||||
do {
|
||||
$proceed = 0;
|
||||
$delim_pos = strpos($rest, $delim, $pos);
|
||||
if ($delim_pos === false) break;
|
||||
$new_rest = substr($rest, $delim_pos + strlen($delim));
|
||||
$r = substr($rest, 0, $delim_pos);
|
||||
if (!preg_match('/([\x5c]+)$/s', $r, $m) || !(strlen($m[1]) % 2)) {
|
||||
$rest = $new_rest;
|
||||
}
|
||||
else {
|
||||
$r = false;
|
||||
$pos = $delim_pos + 1;
|
||||
$proceed = 1;
|
||||
}
|
||||
} while ($proceed);
|
||||
if ($r !== false) {
|
||||
return array(array('value' => $this->toUTF8($r) , 'type' => 'literal', 'sub_type' => $sub_type), $rest);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 67 */
|
||||
|
||||
function xIRIref($v) {
|
||||
if ((list($r, $v) = $this->xIRI_REF($v)) && $r) {
|
||||
return array($this->calcURI($r, $this->base), $v);
|
||||
}
|
||||
elseif ((list($r, $v) = $this->xPrefixedName($v)) && $r) {
|
||||
return array($r, $v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 68 */
|
||||
|
||||
function xPrefixedName($v) {
|
||||
if ((list($r, $v) = $this->xPNAME_LN($v)) && $r) {
|
||||
return array($r, $v);
|
||||
}
|
||||
elseif ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
|
||||
return isset($this->prefixes[$r]) ? array($this->prefixes[$r], $sub_v) : array(0, $v);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 69.., 73.., 93, 94.. */
|
||||
|
||||
function xBlankNode($v) {
|
||||
if (($r = $this->x('\_\:', $v)) && (list($r, $sub_v) = $this->xPN_LOCAL($r[1])) && $r) {
|
||||
return array(array('type' => 'bnode', 'value' => '_:' . $r), $sub_v);
|
||||
}
|
||||
if ($r = $this->x('\[[\x20\x9\xd\xa]*\]', $v)) {
|
||||
return array(array('type' => 'bnode', 'value' => $this->createBnodeID()), $r[1]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 70.. */
|
||||
|
||||
function xIRI_REF($v) {
|
||||
//if ($r = $this->x('\<([^\<\>\"\{\}\|\^\'[:space:]]*)\>', $v)) {
|
||||
if (($r = $this->x('\<(\$\{[^\>]*\})\>', $v)) && ($sub_r = $this->xPlaceholder($r[1]))) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
elseif ($r = $this->x('\<\>', $v)) {
|
||||
return array(true, $r[1]);
|
||||
}
|
||||
elseif ($r = $this->x('\<([^\s][^\<\>]*)\>', $v)) {
|
||||
return array($r[1] ? $r[1] : true, $r[2]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 71 */
|
||||
|
||||
function xPNAME_NS($v) {
|
||||
list($r, $sub_v) = $this->xPN_PREFIX($v);
|
||||
$prefix = $r ? $r : '';
|
||||
return ($r = $this->x("\:", $sub_v)) ? array($prefix . ':', $r[1]) : array(0, $v);
|
||||
}
|
||||
|
||||
/* 72 */
|
||||
|
||||
function xPNAME_LN($v) {
|
||||
if ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
|
||||
if (!$this->x('\s', $sub_v) && (list($sub_r, $sub_v) = $this->xPN_LOCAL($sub_v)) && $sub_r) {
|
||||
if (!isset($this->prefixes[$r])) {
|
||||
return array(0, $v);
|
||||
}
|
||||
return array($this->prefixes[$r] . $sub_r, $sub_v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 76 */
|
||||
|
||||
function xLANGTAG($v) {
|
||||
if (!$this->x('\s', $v) && ($r = $this->x('\@([a-z]+(\-[a-z0-9]+)*)', $v))) {
|
||||
return array($r[1], $r[3]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 77.. */
|
||||
|
||||
function xINTEGER($v) {
|
||||
if ($r = $this->x('([0-9]+)', $v)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
return array(false, $v);
|
||||
}
|
||||
|
||||
/* 78.. */
|
||||
|
||||
function xDECIMAL($v) {
|
||||
if ($r = $this->x('([0-9]+\.[0-9]*)', $v)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
if ($r = $this->x('(\.[0-9]+)', $v)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
return array(false, $v);
|
||||
}
|
||||
|
||||
/* 79.., 86.. */
|
||||
|
||||
function xDOUBLE($v) {
|
||||
if ($r = $this->x('([0-9]+\.[0-9]*E[\+\-]?[0-9]+)', $v)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
if ($r = $this->x('(\.[0-9]+E[\+\-]?[0-9]+)', $v)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
if ($r = $this->x('([0-9]+E[\+\-]?[0-9]+)', $v)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
return array(false, $v);
|
||||
}
|
||||
|
||||
/* 92 */
|
||||
|
||||
function xNIL($v) {
|
||||
if ($r = $this->x('\([\x20\x9\xd\xa]*\)', $v)) {
|
||||
return array(array('type' => 'uri', 'value' => $this->rdf . 'nil'), $r[1]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 95.. */
|
||||
|
||||
function xPN_CHARS_BASE($v) {
|
||||
if ($r = $this->x("([a-z]+|\\\u[0-9a-f]{1,4})", $v)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 96 */
|
||||
|
||||
function xPN_CHARS_U($v) {
|
||||
if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
elseif ($r = $this->x("(_)", $v)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* 97.. */
|
||||
|
||||
function xVARNAME($v) {
|
||||
$r = '';
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ($sub_r = $this->x('([0-9]+)', $v)) {
|
||||
$r .= $sub_r[1];
|
||||
$v = $sub_r[2];
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($v)) && $sub_r) {
|
||||
$r .= $sub_r;
|
||||
$v = $sub_v;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ($r && ($sub_r = $this->x('([\xb7\x300-\x36f]+)', $v))) {
|
||||
$r .= $sub_r[1];
|
||||
$v = $sub_r[2];
|
||||
$proceed = 1;
|
||||
}
|
||||
} while ($proceed);
|
||||
return array($r, $v);
|
||||
}
|
||||
|
||||
/* 98.. */
|
||||
|
||||
function xPN_CHARS($v) {
|
||||
if ((list($r, $sub_v) = $this->xPN_CHARS_U($v)) && $r) {
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
elseif ($r = $this->x('([\-0-9\xb7\x300-\x36f])', $v)) {
|
||||
return array($r[1], $r[2]);
|
||||
}
|
||||
return array(false, $v);
|
||||
}
|
||||
|
||||
/* 99 */
|
||||
|
||||
function xPN_PREFIX($v) {
|
||||
if ($sub_r = $this->x("([^\s\:\(\)\{\}\;\,]+)", $v, 's')) {/* accelerator */
|
||||
return array($sub_r[1], $sub_r[2]);/* @@testing */
|
||||
}
|
||||
if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
|
||||
do {
|
||||
$proceed = 0;
|
||||
list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
|
||||
if ($sub_r !== false) {
|
||||
$r .= $sub_r;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ($sub_r = $this->x("\.", $sub_v)) {
|
||||
$r .= '.';
|
||||
$sub_v = $sub_r[1];
|
||||
$proceed = 1;
|
||||
}
|
||||
} while ($proceed);
|
||||
list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
|
||||
$r .= $sub_r ? $sub_r : '';
|
||||
}
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
|
||||
/* 100 */
|
||||
|
||||
function xPN_LOCAL($v) {
|
||||
if (($sub_r = $this->x("([^\s\(\)\{\}\;\,\.]+)", $v, 's')) && !preg_match('/^\./', $sub_r[2])) {/* accelerator */
|
||||
return array($sub_r[1], $sub_r[2]);/* @@testing */
|
||||
}
|
||||
$r = '';
|
||||
$sub_v = $v;
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ($this->x('\s', $sub_v)) {
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
if ($sub_r = $this->x('([0-9])', $sub_v)) {
|
||||
$r .= $sub_r[1];
|
||||
$sub_v = $sub_r[2];
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($sub_v)) && $sub_r) {
|
||||
$r .= $sub_r;
|
||||
$proceed = 1;
|
||||
}
|
||||
elseif ($r) {
|
||||
if (($sub_r = $this->x('(\.)', $sub_v)) && !preg_match('/^\s/s', $sub_r[2])) {
|
||||
$r .= $sub_r[1];
|
||||
$sub_v = $sub_r[2];
|
||||
}
|
||||
if ((list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v)) && $sub_r) {
|
||||
$r .= $sub_r;
|
||||
$proceed = 1;
|
||||
}
|
||||
}
|
||||
} while ($proceed);
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function unescapeNtripleUTF($v) {
|
||||
if (strpos($v, '\\') === false) return $v;
|
||||
$mappings = array('t' => "\t", 'n' => "\n", 'r' => "\r", '\"' => '"', '\'' => "'");
|
||||
foreach ($mappings as $in => $out) {
|
||||
$v = preg_replace('/\x5c([' . $in . '])/', $out, $v);
|
||||
}
|
||||
if (strpos(strtolower($v), '\u') === false) return $v;
|
||||
while (preg_match('/\\\(U)([0-9A-F]{8})/', $v, $m) || preg_match('/\\\(u)([0-9A-F]{4})/', $v, $m)) {
|
||||
$no = hexdec($m[2]);
|
||||
if ($no < 128) $char = chr($no);
|
||||
else if ($no < 2048) $char = chr(($no >> 6) + 192) . chr(($no & 63) + 128);
|
||||
else if ($no < 65536) $char = chr(($no >> 12) + 224) . chr((($no >> 6) & 63) + 128) . chr(($no & 63) + 128);
|
||||
else if ($no < 2097152) $char = chr(($no >> 18) + 240) . chr((($no >> 12) & 63) + 128) . chr((($no >> 6) & 63) + 128) . chr(($no & 63) + 128);
|
||||
else $char= '';
|
||||
$v = str_replace('\\' . $m[1] . $m[2], $char, $v);
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function xPlaceholder($v) {
|
||||
//if ($r = $this->x('(\?|\$)\{([^\}]+)\}', $v)) {
|
||||
if ($r = $this->x('(\?|\$)', $v)) {
|
||||
if (preg_match('/(\{(?:[^{}]+|(?R))*\})/', $r[2], $m) && strpos(trim($r[2]), $m[1]) === 0) {
|
||||
$ph = substr($m[1], 1, -1);
|
||||
$rest = substr(trim($r[2]), strlen($m[1]));
|
||||
if (!isset($this->r['placeholders'])) $this->r['placeholders'] = array();
|
||||
if (!in_array($ph, $this->r['placeholders'])) $this->r['placeholders'][] = $ph;
|
||||
return array(array('value' => $ph, 'type' => 'placeholder'), $rest);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* */
|
||||
}
|
||||
53
arc/serializers/ARC2_LegacyHTMLSerializer.php
Normal file
53
arc/serializers/ARC2_LegacyHTMLSerializer.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Legacy XML Serializer
|
||||
author: Benjamin Nowack
|
||||
version: 2008-08-04
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_LegacyHTMLSerializer extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_LegacyHTMLSerializer($a = '', &$caller) {/* ns */
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->content_header = 'text/html';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getSerializedArray($struct, $root = 1, $ind = ' ') {
|
||||
$n = "\n";
|
||||
$r = '';
|
||||
$is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
|
||||
foreach ($struct as $k => $v) {
|
||||
if (!$is_flat) $r .= $n . $ind . $ind . '<dt>' . $k . '</dt>';
|
||||
$r .= $n . $ind . $ind . '<dd>' . (is_array($v) ? $this->getSerializedArray($v, 0, $ind . $ind . $ind) . $n . $ind . $ind : htmlspecialchars($v)) . '</dd>';
|
||||
}
|
||||
return $n . $ind . '<dl>' . $r . $n . $ind . '</dl>';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function isAssociativeArray($v) {
|
||||
foreach (array_keys($v) as $k => $val) {
|
||||
if ($k !== $val) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
|
||||
57
arc/serializers/ARC2_LegacyJSONSerializer.php
Normal file
57
arc/serializers/ARC2_LegacyJSONSerializer.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Legacy JSON Serializer
|
||||
author: Benjamin Nowack
|
||||
version: 2008-08-04
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_LegacyJSONSerializer extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_LegacyJSONSerializer($a = '', &$caller) {/* ns */
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->content_header = 'application/json';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getSerializedArray($struct, $ind = '') {
|
||||
$n = "\n";
|
||||
if (function_exists('json_encode')) return str_replace('","', '",' . $n . '"', json_encode($struct));
|
||||
$r = '';
|
||||
$from = array("\\", "\r", "\t", "\n", '"', "\b", "\f", "/");
|
||||
$to = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\foo/');
|
||||
$is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
|
||||
foreach ($struct as $k => $v) {
|
||||
$r .= $r ? ',' . $n . $ind . $ind : $ind . $ind;
|
||||
$r .= $is_flat ? '' : '"' . $k . '": ';
|
||||
$r .= is_array($v) ? $this->getSerializedArray($v, $ind . ' ') : '"' . str_replace($from, $to, $v) . '"';
|
||||
}
|
||||
return $is_flat ? $ind . '[' . $n . $r . $n . $ind . ']' : $ind . '{' . $n . $r . $n . $ind . '}';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function isAssociativeArray($v) {
|
||||
foreach (array_keys($v) as $k => $val) {
|
||||
if ($k !== $val) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
|
||||
70
arc/serializers/ARC2_LegacyXMLSerializer.php
Normal file
70
arc/serializers/ARC2_LegacyXMLSerializer.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Legacy XML Serializer
|
||||
author: Benjamin Nowack
|
||||
version: 2008-08-04
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_LegacyXMLSerializer extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_LegacyXMLSerializer($a = '', &$caller) {/* ns */
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->content_header = 'text/xml';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getSerializedArray($struct, $root = 1, $ind = ' ') {
|
||||
$n = "\n";
|
||||
$r = '';
|
||||
$is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
|
||||
foreach ($struct as $k => $v) {
|
||||
$tag = $is_flat ? 'item' : preg_replace('/[\s]/s', '_', $k);
|
||||
$tag = preg_replace('/^.*([a-z0-9\-\_]+)$/Uis', '\\1', $tag);
|
||||
$r .= $n . $ind . '<' . $tag . '>' . (is_array($v) ? $this->getSerializedArray($v, 0, $ind . ' ') . $n . $ind : htmlspecialchars($v)) . '</' . $tag . '>';
|
||||
}
|
||||
if ($root) $r = $this->getHead() . $r . $this->getFooter();
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getHead() {
|
||||
$n = "\n";
|
||||
$r = '<?xml version="1.0"?>';
|
||||
$r .= $n . '<items>';
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getFooter() {
|
||||
$n = "\n";
|
||||
$r = $n . '</items>';
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function isAssociativeArray($v) {
|
||||
foreach (array_keys($v) as $k => $val) {
|
||||
if ($k !== $val) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
|
||||
146
arc/serializers/ARC2_NTriplesSerializer.php
Normal file
146
arc/serializers/ARC2_NTriplesSerializer.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 N-Triples Serializer
|
||||
author: Benjamin Nowack
|
||||
version: 2008-09-11 (Fix: improved literal/uri detection
|
||||
Addition: Support for "raw" (turtle-like) terms)
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFSerializer');
|
||||
|
||||
class ARC2_NTriplesSerializer extends ARC2_RDFSerializer {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_NTriplesSerializer($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->esc_chars = array();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTerm($v) {
|
||||
if (!is_array($v)) {
|
||||
if (preg_match('/^\_\:/', $v)) {
|
||||
return $v;
|
||||
}
|
||||
if (preg_match('/^[a-z0-9]+\:[^\s]*$/is', $v)) {
|
||||
return '<' . $this->escape($v) . '>';
|
||||
}
|
||||
return $this->getTerm(array('type' => 'literal', 'value' => $v));
|
||||
}
|
||||
if ($v['type'] != 'literal') {
|
||||
return $this->getTerm($v['value']);
|
||||
}
|
||||
/* literal */
|
||||
$quot = '"';
|
||||
if (preg_match('/\"/', $v['value'])) {
|
||||
$quot = "'";
|
||||
if (preg_match('/\'/', $v['value'])) {
|
||||
$quot = '"""';
|
||||
if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
|
||||
$quot = "'''";
|
||||
$v['value'] = preg_replace("/'$/", "' ", $v['value']);
|
||||
$v['value'] = preg_replace("/^'/", " '", $v['value']);
|
||||
$v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((strlen($quot) == 1) && preg_match('/[\x0d\x0a]/', $v['value'])) {
|
||||
$quot = $quot . $quot . $quot;
|
||||
}
|
||||
$suffix = isset($v['lang']) && $v['lang'] ? '@' . $v['lang'] : '';
|
||||
$suffix = isset($v['datatype']) && $v['datatype'] ? '^^' . $this->getTerm($v['datatype']) : $suffix;
|
||||
//return $quot . "object" . utf8_encode($v['value']) . $quot . $suffix;
|
||||
return $quot . $this->escape($v['value']) . $quot . $suffix;
|
||||
}
|
||||
|
||||
function getSerializedIndex($index, $raw = 0) {
|
||||
$this->raw = $raw;
|
||||
$r = '';
|
||||
$nl = "\n";
|
||||
foreach ($index as $s => $ps) {
|
||||
$s = $this->getTerm($s);
|
||||
foreach ($ps as $p => $os) {
|
||||
$p = $this->getTerm($p);
|
||||
if (!is_array($os)) {/* single literal o */
|
||||
$os = array(array('value' => $os, 'type' => 'literal'));
|
||||
}
|
||||
foreach ($os as $o) {
|
||||
$o = $this->getTerm($o);
|
||||
$r .= $r ? $nl : '';
|
||||
$r .= $s . ' ' . $p . ' ' . $o . ' .';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $r . $nl;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function escape($v) {
|
||||
$r = '';
|
||||
$v = (strpos(utf8_decode(str_replace('?', '', $v)), '?') === false) ? utf8_decode($v) : $v;
|
||||
if ($this->raw) return $v;
|
||||
for ($i = 0, $i_max = strlen($v); $i < $i_max; $i++) {
|
||||
$c = $v[$i];
|
||||
if (!isset($this->esc_chars[$c])) {
|
||||
$this->esc_chars[$c] = $this->getEscapedChar($c, $this->getCharNo($c));
|
||||
}
|
||||
$r .= $this->esc_chars[$c];
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getCharNo($c) {
|
||||
$c_utf = utf8_encode($c);
|
||||
$bl = strlen($c_utf);/* binary length */
|
||||
$r = 0;
|
||||
switch ($bl) {
|
||||
case 1:/* 0####### (0-127) */
|
||||
$r = ord($c_utf);
|
||||
break;
|
||||
case 2:/* 110##### 10###### = 192+x 128+x */
|
||||
$r = ((ord($c_utf[0]) - 192) * 64) + (ord($c_utf[1]) - 128);
|
||||
break;
|
||||
case 3:/* 1110#### 10###### 10###### = 224+x 128+x 128+x */
|
||||
$r = ((ord($c_utf[0]) - 224) * 4096) + ((ord($c_utf[1]) - 128) * 64) + (ord($c_utf[2]) - 128);
|
||||
break;
|
||||
case 4:/* 1111#### 10###### 10###### 10###### = 240+x 128+x 128+x 128+x */
|
||||
$r = ((ord($c_utf[0]) - 240) * 262144) + ((ord($c_utf[1]) - 128) * 4096) + ((ord($c_utf[2]) - 128) * 64) + (ord($c_utf[3]) - 128);
|
||||
break;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getEscapedChar($c, $no) {/*see http://www.w3.org/TR/rdf-testcases/#ntrip_strings */
|
||||
if ($no < 9) return "\\u" . sprintf('%04X', $no); /* #x0-#x8 (0-8) */
|
||||
if ($no == 9) return '\t'; /* #x9 (9) */
|
||||
if ($no == 10) return '\n'; /* #xA (10) */
|
||||
if ($no < 13) return "\\u" . sprintf('%04X', $no); /* #xB-#xC (11-12) */
|
||||
if ($no == 13) return '\r'; /* #xD (13) */
|
||||
if ($no < 32) return "\\u" . sprintf('%04X', $no); /* #xE-#x1F (14-31) */
|
||||
if ($no < 34) return $c; /* #x20-#x21 (32-33) */
|
||||
if ($no == 34) return '\"'; /* #x22 (34) */
|
||||
if ($no < 92) return $c; /* #x23-#x5B (35-91) */
|
||||
if ($no == 92) return '\\'; /* #x5C (92) */
|
||||
if ($no < 127) return $c; /* #x5D-#x7E (93-126) */
|
||||
if ($no < 65536) return "\\u" . sprintf('%04X', $no); /* #x7F-#xFFFF (128-65535) */
|
||||
if ($no < 1114112) return "\\U" . sprintf('%08X', $no); /* #x10000-#x10FFFF (65536-1114111) */
|
||||
return ''; /* not defined => ignore */
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
109
arc/serializers/ARC2_POSHRDFSerializer.php
Normal file
109
arc/serializers/ARC2_POSHRDFSerializer.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 POSH RDF Serializer
|
||||
author: Benjamin Nowack
|
||||
version: 2008-11-18 (Tweak: Updated to poshRDF spec draft)
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFSerializer');
|
||||
|
||||
class ARC2_POSHRDFSerializer extends ARC2_RDFSerializer {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_POSHRDFSerializer($a = '', &$caller) {/* ns */
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->content_header = 'text/html';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getLabel($res, $ps = '') {
|
||||
if (!$ps) $ps = array();
|
||||
foreach ($ps as $p => $os) {
|
||||
if (preg_match('/[\/\#](name|label|summary|title|fn)$/i', $p)) {
|
||||
return $os[0]['value'];
|
||||
}
|
||||
}
|
||||
if (preg_match('/^\_\:/', $res)) return "An unnamed resource";
|
||||
return preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('_', ' ', $res));
|
||||
}
|
||||
|
||||
function getSerializedIndex($index, $res = '') {
|
||||
$r = '';
|
||||
$n = "\n";
|
||||
if ($res) $index = array($res => $index[$res]);
|
||||
//return Trice::dump($index);
|
||||
foreach ($index as $s => $ps) {
|
||||
/* node */
|
||||
$r .= '
|
||||
<div class="rdf-view">
|
||||
<h3><a class="rdf-s" href="' . $s . '">' . $this->getLabel($s, $ps) . '</a></h3>
|
||||
';
|
||||
/* arcs */
|
||||
foreach ($ps as $p => $os) {
|
||||
$r .= '
|
||||
<div class="rdf-o-list">
|
||||
<a class="rdf-p" href="' . $p . '">' . ucfirst($this->getLabel($p)) . '</a>
|
||||
';
|
||||
foreach ($os as $o) {
|
||||
$r .= $n . $this->getObjectValue($o);
|
||||
}
|
||||
$r .= '
|
||||
</div>
|
||||
';
|
||||
}
|
||||
/* node */
|
||||
$r .= '
|
||||
<div class="clb"></div>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getObjectValue($o) {
|
||||
if ($o['type'] == 'uri') {
|
||||
if (preg_match('/(jpe?g|gif|png)$/i', $o['value'])) {
|
||||
return $this->getImageObjectValue($o);
|
||||
}
|
||||
return $this->getURIObjectValue($o);
|
||||
}
|
||||
if ($o['type'] == "bnode") {
|
||||
return $this->getBNodeObjectValue($o);
|
||||
}
|
||||
return $this->getLiteralObjectValue($o);
|
||||
}
|
||||
|
||||
function getImageObjectValue($o) {
|
||||
return '<img class="rdf-o" src="' . htmlspecialchars($o['value']) . '" alt="img" />';
|
||||
}
|
||||
|
||||
function getURIObjectValue($o) {
|
||||
$href = htmlspecialchars($o['value']);
|
||||
$label = $o['value'];
|
||||
$label = preg_replace('/^https?\:\/\/(www\.)?/', '', $label);
|
||||
return '<a class="rdf-o" href="' . $href . '">' . $label . '</a>';
|
||||
}
|
||||
|
||||
function getBNodeObjectValue($o) {
|
||||
return '<div class="rdf-o" title="' . $o['value']. '">An unnamed resource</div>';
|
||||
}
|
||||
|
||||
function getLiteralObjectValue($o) {
|
||||
return '<div class="rdf-o">' . $o['value'] . '</div>';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
|
||||
91
arc/serializers/ARC2_RDFJSONSerializer.php
Normal file
91
arc/serializers/ARC2_RDFJSONSerializer.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 RDF/JSON Serializer
|
||||
author: Benjamin Nowack
|
||||
version: 2008-07-01 (Fix: Proper jsonEscape method, thx to Keith Alexander)
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFSerializer');
|
||||
|
||||
class ARC2_RDFJSONSerializer extends ARC2_RDFSerializer {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_RDFJSONSerializer($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->content_header = 'application/json';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTerm($v, $term = 's') {
|
||||
if (!is_array($v)) {
|
||||
if (preg_match('/^\_\:/', $v)) {
|
||||
return ($term == 'o') ? $this->getTerm(array('value' => $v, 'type' => 'bnode'), 'o') : '"' . $v . '"';
|
||||
}
|
||||
return ($term == 'o') ? $this->getTerm(array('value' => $v, 'type' => 'uri'), 'o') : '"' . $v . '"';
|
||||
}
|
||||
if (!isset($v['type']) || ($v['type'] != 'literal')) {
|
||||
if ($term != 'o') {
|
||||
return $this->getTerm($v['value'], $term);
|
||||
}
|
||||
if (preg_match('/^\_\:/', $v['value'])) {
|
||||
return '{ "value" : "' . $v['value']. '", "type" : "bnode" }';
|
||||
}
|
||||
return '{ "value" : "' . $v['value']. '", "type" : "uri" }';
|
||||
}
|
||||
/* literal */
|
||||
$r = '{ "value" : "' . $this->jsonEscape($v['value']). '", "type" : "literal"';
|
||||
$suffix = isset($v['datatype']) ? ', "datatype" : "' . $v['datatype'] . '"' : '';
|
||||
$suffix = isset($v['lang']) ? ', "lang" : "' . $v['lang'] . '"' : $suffix;
|
||||
$r .= $suffix . ' }';
|
||||
return $r;
|
||||
}
|
||||
|
||||
function jsonEscape($v) {
|
||||
if (function_exists('json_encode')) return trim(json_encode($v), '"');
|
||||
$from = array("\\", "\r", "\t", "\n", '"', "\b", "\f", "/");
|
||||
$to = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\foo/');
|
||||
return str_replace($from, $to, $v);
|
||||
}
|
||||
|
||||
function getSerializedIndex($index) {
|
||||
$r = '';
|
||||
$nl = "\n";
|
||||
foreach ($index as $s => $ps) {
|
||||
$r .= $r ? ',' . $nl . $nl : '';
|
||||
$r .= ' ' . $this->getTerm($s). ' : {';
|
||||
$first_p = 1;
|
||||
foreach ($ps as $p => $os) {
|
||||
$r .= $first_p ? $nl : ',' . $nl;
|
||||
$r .= ' ' . $this->getTerm($p). ' : [';
|
||||
$first_o = 1;
|
||||
if (!is_array($os)) {/* single literal o */
|
||||
$os = array(array('value' => $os, 'type' => 'literal'));
|
||||
}
|
||||
foreach ($os as $o) {
|
||||
$r .= $first_o ? $nl : ',' . $nl;
|
||||
$r .= ' ' . $this->getTerm($o, 'o');
|
||||
$first_o = 0;
|
||||
}
|
||||
$first_p = 0;
|
||||
$r .= $nl . ' ]';
|
||||
}
|
||||
$r .= $nl . ' }';
|
||||
}
|
||||
$r .= $r ? ' ' : '';
|
||||
return '{' . $nl . $r . $nl . '}';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
57
arc/serializers/ARC2_RDFSerializer.php
Normal file
57
arc/serializers/ARC2_RDFSerializer.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 RDF Serializer
|
||||
*
|
||||
* @author Benjamin Nowack
|
||||
* @license <http://arc.semsol.org/license>
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-11-09
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_RDFSerializer extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_RDFSerializer($a = '', &$caller) {/* ns */
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
foreach ($this->ns as $k => $v) {
|
||||
$this->nsp[$v] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function xgetPName($v) {/* moved to merged getPName in ARC2_CLass */
|
||||
if (preg_match('/^([a-z0-9\_\-]+)\:([a-z\_][a-z0-9\_\-]*)$/i', $v, $m) && isset($this->ns[$m[1]])) {
|
||||
$this->used_ns = !in_array($this->ns[$m[1]], $this->used_ns) ? array_merge($this->used_ns, array($this->ns[$m[1]])) : $this->used_ns;
|
||||
return $v;
|
||||
}
|
||||
if (preg_match('/^(.*[\/\#])([a-z\_][a-z0-9\-\_]*)$/i', $v, $m)) {
|
||||
return $this->getPrefix($m[1]) . ':' . $m[2];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getSerializedTriples($triples, $raw = 0) {
|
||||
$index = ARC2::getSimpleIndex($triples, 0);
|
||||
return $this->getSerializedIndex($index, $raw);
|
||||
}
|
||||
|
||||
function getSerializedIndex() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
199
arc/serializers/ARC2_RDFXMLSerializer.php
Normal file
199
arc/serializers/ARC2_RDFXMLSerializer.php
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 RDF/XML Serializer
|
||||
*
|
||||
* @author Benjamin Nowack
|
||||
* @license <http://arc.semsol.org/license>
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-12-03
|
||||
*
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFSerializer');
|
||||
|
||||
class ARC2_RDFXMLSerializer extends ARC2_RDFSerializer {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_RDFXMLSerializer($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->content_header = 'application/rdf+xml';
|
||||
$this->pp_containers = $this->v('serializer_prettyprint_containers', 0, $this->a);
|
||||
$this->default_ns = $this->v('serializer_default_ns', '', $this->a);
|
||||
$this->type_nodes = $this->v('serializer_type_nodes', 0, $this->a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTerm($v, $type) {
|
||||
if (!is_array($v)) {/* uri or bnode */
|
||||
if (preg_match('/^\_\:(.*)$/', $v, $m)) {
|
||||
return ' rdf:nodeID="' . $m[1] . '"';
|
||||
}
|
||||
if ($type == 's') {
|
||||
return ' rdf:about="' . htmlspecialchars($v) . '"';
|
||||
}
|
||||
if ($type == 'p') {
|
||||
if ($pn = $this->getPName($v)) {
|
||||
return $pn;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if ($type == 'o') {
|
||||
$v = $this->expandPName($v);
|
||||
if (!preg_match('/^[a-z0-9]{2,}\:[^\s]+$/is', $v)) return $this->getTerm(array('value' => $v, 'type' => 'literal'), $type);
|
||||
return ' rdf:resource="' . htmlspecialchars($v) . '"';
|
||||
}
|
||||
if ($type == 'datatype') {
|
||||
$v = $this->expandPName($v);
|
||||
return ' rdf:datatype="' . htmlspecialchars($v) . '"';
|
||||
}
|
||||
if ($type == 'lang') {
|
||||
return ' xml:lang="' . htmlspecialchars($v) . '"';
|
||||
}
|
||||
}
|
||||
if ($v['type'] != 'literal') {
|
||||
return $this->getTerm($v['value'], 'o');
|
||||
}
|
||||
/* literal */
|
||||
$dt = isset($v['datatype']) ? $v['datatype'] : '';
|
||||
$lang = isset($v['lang']) ? $v['lang'] : '';
|
||||
if ($dt == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral') {
|
||||
return ' rdf:parseType="Literal">' . $v['value'];
|
||||
}
|
||||
elseif ($dt) {
|
||||
return $this->getTerm($dt, 'datatype') . '>' . htmlspecialchars($v['value']);
|
||||
}
|
||||
elseif ($lang) {
|
||||
return $this->getTerm($lang, 'lang') . '>' . htmlspecialchars($v['value']);
|
||||
}
|
||||
return '>' . htmlspecialchars($v['value']);
|
||||
}
|
||||
|
||||
function getPName($v, $connector = ':') {
|
||||
if ($this->default_ns && (strpos($v, $this->default_ns) === 0)) {
|
||||
return substr($v, strlen($this->default_ns));
|
||||
}
|
||||
return parent::getPName($v, $connector);
|
||||
}
|
||||
|
||||
function getHead() {
|
||||
$r = '';
|
||||
$nl = "\n";
|
||||
$r .= '<?xml version="1.0" encoding="UTF-8"?>';
|
||||
$r .= $nl . '<rdf:RDF';
|
||||
$first_ns = 1;
|
||||
foreach ($this->used_ns as $v) {
|
||||
$r .= $first_ns ? ' ' : $nl . ' ';
|
||||
$r .= 'xmlns:' . $this->nsp[$v] . '="' .$v. '"';
|
||||
$first_ns = 0;
|
||||
}
|
||||
if ($this->default_ns) {
|
||||
$r .= $first_ns ? ' ' : $nl . ' ';
|
||||
$r .= 'xmlns="' . $this->default_ns . '"';
|
||||
}
|
||||
$r .= '>';
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getFooter() {
|
||||
$r = '';
|
||||
$nl = "\n";
|
||||
$r .= $nl . $nl . '</rdf:RDF>';
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getSerializedIndex($index, $raw = 0) {
|
||||
$r = '';
|
||||
$nl = "\n";
|
||||
foreach ($index as $raw_s => $ps) {
|
||||
$r .= $r ? $nl . $nl : '';
|
||||
$s = $this->getTerm($raw_s, 's');
|
||||
$tag = 'rdf:Description';
|
||||
list($tag, $ps) = $this->getNodeTag($ps);
|
||||
$sub_ps = 0;
|
||||
/* pretty containers */
|
||||
if ($this->pp_containers && ($ctag = $this->getContainerTag($ps))) {
|
||||
$tag = 'rdf:' . $ctag;
|
||||
list($ps, $sub_ps) = $this->splitContainerEntries($ps);
|
||||
}
|
||||
$r .= ' <' . $tag . '' .$s . '>';
|
||||
$first_p = 1;
|
||||
foreach ($ps as $p => $os) {
|
||||
if (!$os) continue;
|
||||
if ($p = $this->getTerm($p, 'p')) {
|
||||
$r .= $nl . str_pad('', 4);
|
||||
$first_o = 1;
|
||||
if (!is_array($os)) {/* single literal o */
|
||||
$os = array(array('value' => $os, 'type' => 'literal'));
|
||||
}
|
||||
foreach ($os as $o) {
|
||||
$o = $this->getTerm($o, 'o');
|
||||
$r .= $first_o ? '' : $nl . ' ';
|
||||
$r .= '<' . $p;
|
||||
$r .= $o;
|
||||
$r .= preg_match('/\>/', $o) ? '</' . $p . '>' : '/>';
|
||||
$first_o = 0;
|
||||
}
|
||||
$first_p = 0;
|
||||
}
|
||||
}
|
||||
$r .= $r ? $nl . ' </' . $tag . '>' : '';
|
||||
if ($sub_ps) $r .= $nl . $nl . $this->getSerializedIndex(array($raw_s => $sub_ps), 1);
|
||||
}
|
||||
if ($raw) {
|
||||
return $r;
|
||||
}
|
||||
return $this->getHead() . $nl . $nl . $r . $this->getFooter();
|
||||
}
|
||||
|
||||
function getNodeTag($ps) {
|
||||
if (!$this->type_nodes) return array('rdf:Description', $ps);
|
||||
$rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
$types = $this->v($rdf . 'type', array(), $ps);
|
||||
if (!$types) return array('rdf:Description', $ps);
|
||||
$type = array_shift($types);
|
||||
$ps[$rdf . 'type'] = $types;
|
||||
if (!is_array($type)) $type = array('value' => $type);
|
||||
return array($this->getPName($type['value']), $ps);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getContainerTag($ps) {
|
||||
$rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
if (!isset($ps[$rdf . 'type'])) return '';
|
||||
$types = $ps[$rdf . 'type'];
|
||||
foreach ($types as $type) {
|
||||
if (!in_array($type['value'], array($rdf . 'Bag', $rdf . 'Seq', $rdf . 'Alt'))) return '';
|
||||
return str_replace($rdf, '', $type['value']);
|
||||
}
|
||||
}
|
||||
|
||||
function splitContainerEntries($ps) {
|
||||
$rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||
$items = array();
|
||||
$rest = array();
|
||||
foreach ($ps as $p => $os) {
|
||||
$p_short = str_replace($rdf, '', $p);
|
||||
if ($p_short === 'type') continue;
|
||||
if (preg_match('/^\_([0-9]+)$/', $p_short, $m)) {
|
||||
$items = array_merge($items, $os);
|
||||
}
|
||||
else {
|
||||
$rest[$p] = $os;
|
||||
}
|
||||
}
|
||||
if ($items) return array(array($rdf . 'li' => $items), $rest);
|
||||
return array($rest, 0);
|
||||
}
|
||||
|
||||
/* */
|
||||
}
|
||||
34
arc/serializers/ARC2_RSS10Serializer.php
Normal file
34
arc/serializers/ARC2_RSS10Serializer.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 RSS 1.0 Serializer
|
||||
*
|
||||
* @author Toby Inkster
|
||||
* @author Benjamin Nowack
|
||||
* @license <http://arc.semsol.org/license>
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-11-09
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFXMLSerializer');
|
||||
|
||||
class ARC2_RSS10Serializer extends ARC2_RDFXMLSerializer {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_RSS10Serializer($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->content_header = 'application/rss+xml';
|
||||
$this->default_ns = 'http://purl.org/rss/1.0/';
|
||||
$this->type_nodes = true;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
122
arc/serializers/ARC2_TurtleSerializer.php
Normal file
122
arc/serializers/ARC2_TurtleSerializer.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 Turtle Serializer
|
||||
*
|
||||
* @author Benjamin Nowack
|
||||
* @license http://arc.semsol.org/license
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-11-23
|
||||
*
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFSerializer');
|
||||
|
||||
class ARC2_TurtleSerializer extends ARC2_RDFSerializer {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_TurtleSerializer($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->content_header = 'application/x-turtle';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTerm($v, $term = '', $qualifier = '') {
|
||||
if (!is_array($v)) {
|
||||
if (preg_match('/^\_\:/', $v)) {
|
||||
return $v;
|
||||
}
|
||||
if (($term === 'p') && ($pn = $this->getPName($v))) {
|
||||
return $pn;
|
||||
}
|
||||
if (
|
||||
($term === 'o') &&
|
||||
in_array($qualifier, array('rdf:type', 'rdfs:domain', 'rdfs:range', 'rdfs:subClassOf')) &&
|
||||
($pn = $this->getPName($v))
|
||||
) {
|
||||
return $pn;
|
||||
}
|
||||
if (preg_match('/^[a-z0-9]+\:[^\s]*$/is', $v)) {
|
||||
return '<' .$v. '>';
|
||||
}
|
||||
return $this->getTerm(array('type' => 'literal', 'value' => $v), $term, $qualifier);
|
||||
}
|
||||
if (!isset($v['type']) || ($v['type'] != 'literal')) {
|
||||
return $this->getTerm($v['value'], $term, $qualifier);
|
||||
}
|
||||
/* literal */
|
||||
$quot = '"';
|
||||
if (preg_match('/\"/', $v['value'])) {
|
||||
$quot = "'";
|
||||
if (preg_match('/\'/', $v['value'])) {
|
||||
$quot = '"""';
|
||||
if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
|
||||
$quot = "'''";
|
||||
$v['value'] = preg_replace("/'$/", "' ", $v['value']);
|
||||
$v['value'] = preg_replace("/^'/", " '", $v['value']);
|
||||
$v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((strlen($quot) == 1) && preg_match('/[\x0d\x0a]/', $v['value'])) {
|
||||
$quot = $quot . $quot . $quot;
|
||||
}
|
||||
$suffix = isset($v['lang']) && $v['lang'] ? '@' . $v['lang'] : '';
|
||||
$suffix = isset($v['datatype']) && $v['datatype'] ? '^^' . $this->getTerm($v['datatype'], 'dt') : $suffix;
|
||||
return $quot . $v['value'] . $quot . $suffix;
|
||||
}
|
||||
|
||||
function getHead() {
|
||||
$r = '';
|
||||
$nl = "\n";
|
||||
foreach ($this->used_ns as $v) {
|
||||
$r .= $r ? $nl : '';
|
||||
$r .= '@prefix ' . $this->nsp[$v] . ': <' .$v. '> .';
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getSerializedIndex($index, $raw = 0) {
|
||||
$r = '';
|
||||
$nl = "\n";
|
||||
foreach ($index as $s => $ps) {
|
||||
$r .= $r ? ' .' . $nl . $nl : '';
|
||||
$s = $this->getTerm($s, 's');
|
||||
$r .= $s;
|
||||
$first_p = 1;
|
||||
foreach ($ps as $p => $os) {
|
||||
if (!$os) continue;
|
||||
$p = $this->getTerm($p, 'p');
|
||||
$r .= $first_p ? ' ' : ' ;' . $nl . str_pad('', strlen($s) + 1);
|
||||
$r .= $p;
|
||||
$first_o = 1;
|
||||
if (!is_array($os)) {/* single literal o */
|
||||
$os = array(array('value' => $os, 'type' => 'literal'));
|
||||
}
|
||||
foreach ($os as $o) {
|
||||
$r .= $first_o ? ' ' : ' ,' . $nl . str_pad('', strlen($s) + strlen($p) + 2);
|
||||
$o = $this->getTerm($o, 'o', $p);
|
||||
$r .= $o;
|
||||
$first_o = 0;
|
||||
}
|
||||
$first_p = 0;
|
||||
}
|
||||
}
|
||||
$r .= $r ? ' .' : '';
|
||||
if ($raw) {
|
||||
return $r;
|
||||
}
|
||||
return $r ? $this->getHead() . $nl . $nl . $r : '';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
284
arc/sparqlscript/ARC2_SPARQLScriptParser.php
Normal file
284
arc/sparqlscript/ARC2_SPARQLScriptParser.php
Normal file
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 SPARQLScript Parser (SPARQL+ + functions)
|
||||
author: Benjamin Nowack
|
||||
version: 2008-09-22 (Addition: support for FunctionCall)
|
||||
*/
|
||||
|
||||
ARC2::inc('ARC2_SPARQLPlusParser');
|
||||
|
||||
class ARC2_SPARQLScriptParser extends ARC2_SPARQLPlusParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_SPARQLScriptParser($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function parse($v, $src = '') {
|
||||
$this->setDefaultPrefixes();
|
||||
$this->base = $src ? $this->calcBase($src) : ARC2::getScriptURI();
|
||||
$this->blocks = array();
|
||||
$this->r = array('base' => '', 'vars' => array(), 'prefixes' => $this->prefixes);
|
||||
do {
|
||||
$proceed = 0;
|
||||
if ((list($r, $v) = $this->xScriptBlock($v)) && $r) {
|
||||
$this->blocks[] = $r;
|
||||
$proceed = 1;
|
||||
}
|
||||
$this->unparsed_code = trim($v);
|
||||
} while ($proceed);
|
||||
if (trim($this->unparsed_code) && !$this->getErrors()) {
|
||||
$rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
|
||||
$msg = trim($rest) ? 'Could not properly handle "' . $rest . '"' : 'Syntax Error';
|
||||
$this->addError($msg);
|
||||
}
|
||||
}
|
||||
|
||||
function getScriptBlocks() {
|
||||
return $this->v('blocks', array());
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function xScriptBlock($v) {
|
||||
/* comment removal */
|
||||
while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $v, $m)) $v = $m[2];
|
||||
/* BaseDecl */
|
||||
if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
|
||||
$this->base = $sub_r;
|
||||
}
|
||||
/* PrefixDecl */
|
||||
while ((list($r, $v) = $this->xPrefixDecl($v)) && $r) {
|
||||
$this->prefixes[$r['prefix']] = $r['uri'];
|
||||
}
|
||||
/* EndpointDecl */
|
||||
if ((list($r, $v) = $this->xEndpointDecl($v)) && $r) {
|
||||
return array($r, $v);
|
||||
}
|
||||
/* Return */
|
||||
if ((list($r, $v) = $this->xReturn($v)) && $r) {
|
||||
return array($r, $v);
|
||||
}
|
||||
/* Assignment */
|
||||
if ((list($r, $v) = $this->xAssignment($v)) && $r) {
|
||||
return array($r, $v);
|
||||
}
|
||||
/* IFBlock */
|
||||
if ((list($r, $v) = $this->xIFBlock($v)) && $r) {
|
||||
return array($r, $v);
|
||||
}
|
||||
/* FORBlock */
|
||||
if ((list($r, $v) = $this->xFORBlock($v)) && $r) {
|
||||
return array($r, $v);
|
||||
}
|
||||
/* String */
|
||||
if ((list($r, $v) = $this->xString($v)) && $r) {
|
||||
return array($r, $v);
|
||||
}
|
||||
/* FunctionCall */
|
||||
if ((list($r, $v) = $this->xFunctionCall($v)) && $r) {
|
||||
return array($r, ltrim($v, ';'));
|
||||
}
|
||||
/* Query */
|
||||
$prev_r = $this->r;
|
||||
$this->r = array('base' => '', 'vars' => array(), 'prefixes' => $this->prefixes);
|
||||
if ((list($r, $rest) = $this->xQuery($v)) && $r) {
|
||||
$q = $rest ? trim(substr($v, 0, -strlen($rest))) : trim($v);
|
||||
$v = $rest;
|
||||
$r = array_merge($this->r, array(
|
||||
'type' => 'query',
|
||||
'query_type' => $r['type'],
|
||||
'query' => $q,
|
||||
//'prefixes' => $this->prefixes,
|
||||
'base' => $this->base,
|
||||
//'infos' => $r
|
||||
));
|
||||
return array($r, $v);
|
||||
}
|
||||
else {
|
||||
$this->r = $prev_r;
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
function xBlockSet($v) {
|
||||
if (!$r = $this->x("\{", $v)) return array(0, $v);
|
||||
$blocks = array();
|
||||
$sub_v = $r[1];
|
||||
while ((list($sub_r, $sub_v) = $this->xScriptBlock($sub_v)) && $sub_r) {
|
||||
$blocks[] = $sub_r;
|
||||
}
|
||||
if (!$sub_r = $this->x("\}", $sub_v)) return array(0, $v);
|
||||
$sub_v = $sub_r[1];
|
||||
return array(array('type' => 'block_set', 'blocks' => $blocks), $sub_v);
|
||||
}
|
||||
|
||||
/* s2 */
|
||||
|
||||
function xEndpointDecl($v) {
|
||||
if ($r = $this->x("ENDPOINT\s+", $v)) {
|
||||
if ((list($r, $sub_v) = $this->xIRI_REF($r[1])) && $r) {
|
||||
$r = $this->calcURI($r, $this->base);
|
||||
if ($sub_r = $this->x('\.', $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
}
|
||||
return array(
|
||||
array('type' => 'endpoint_decl', 'endpoint' => $r),
|
||||
$sub_v
|
||||
);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* s3 */
|
||||
|
||||
function xAssignment($v) {
|
||||
/* Var */
|
||||
list($r, $sub_v) = $this->xVar($v);
|
||||
if (!$r) return array(0, $v);
|
||||
$var = $r;
|
||||
/* := | = */
|
||||
if (!$sub_r = $this->x("\:?\=", $sub_v)) return array(0, $v);
|
||||
$sub_v = $sub_r[1];
|
||||
/* try String */
|
||||
list($r, $sub_v) = $this->xString($sub_v);
|
||||
if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'string', 'string' => $r), ltrim($sub_v, '; '));
|
||||
/* try VarMerge */
|
||||
list($r, $sub_v) = $this->xVarMerge($sub_v);
|
||||
if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'var_merge', 'var2' => $r[0], 'var3' => $r[1]), ltrim($sub_v, '; '));
|
||||
/* try Var */
|
||||
list($r, $sub_v) = $this->xVar($sub_v);
|
||||
if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'var', 'var2' => $r), ltrim($sub_v, '; '));
|
||||
/* try function */
|
||||
list($r, $sub_v) = $this->xFunctionCall($sub_v);
|
||||
if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'function_call', 'function_call' => $r), ltrim($sub_v, '; '));
|
||||
/* try Placeholder */
|
||||
list($r, $sub_v) = $this->xPlaceholder($sub_v);
|
||||
if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'placeholder', 'placeholder' => $r), ltrim($sub_v, '; '));
|
||||
/* try query */
|
||||
$prev_r = $this->r;
|
||||
$this->r = array('base' => '', 'vars' => array(), 'prefixes' => $this->prefixes);
|
||||
list($r, $rest) = $this->xQuery($sub_v);
|
||||
if (!$r) {
|
||||
$this->r = $prev_r;
|
||||
return array(0, $v);
|
||||
}
|
||||
else {
|
||||
$q = $rest ? trim(substr($sub_v, 0, -strlen($rest))) : trim($sub_v);
|
||||
return array(
|
||||
array(
|
||||
'type' => 'assignment',
|
||||
'var' => $var,
|
||||
'sub_type' => 'query',
|
||||
'query' => array_merge($this->r, array(
|
||||
'type' => 'query',
|
||||
'query_type' => $r['type'],
|
||||
'query' => $q,
|
||||
'base' => $this->base,
|
||||
)),
|
||||
),
|
||||
ltrim($rest, '; ')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function xReturn($v) {
|
||||
if ($r = $this->x("return\s+", $v)) {
|
||||
/* fake assignment which accepts same right-hand values */
|
||||
$sub_v = '$__return_value__ := ' . $r[1];
|
||||
if ((list($r, $sub_v) = $this->xAssignment($sub_v)) && $r) {
|
||||
$r['type'] = 'return';
|
||||
return array($r, $sub_v);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* s4 'IF' BrackettedExpression '{' Script '}' ( 'ELSE' '{' Script '}')? */
|
||||
|
||||
function xIFBlock($v) {
|
||||
if ($r = $this->x("IF\s*", $v)) {
|
||||
if ((list($sub_r, $sub_v) = $this->xBrackettedExpression($r[1])) && $sub_r) {
|
||||
$cond = $sub_r;
|
||||
if ((list($sub_r, $sub_v) = $this->xBlockSet($sub_v)) && $sub_r) {
|
||||
$blocks = $sub_r['blocks'];
|
||||
/* else */
|
||||
$else_blocks = array();
|
||||
$rest = $sub_v;
|
||||
if ($sub_r = $this->x("ELSE\s*", $sub_v)) {
|
||||
if ((list($sub_r, $sub_v) = $this->xBlockSet($sub_r[1])) && $sub_r) {
|
||||
$else_blocks = $sub_r['blocks'];
|
||||
}
|
||||
else {
|
||||
$sub_v = $rest;
|
||||
}
|
||||
}
|
||||
return array(
|
||||
array(
|
||||
'type' => 'ifblock',
|
||||
'condition' => $cond,
|
||||
'blocks' => $blocks,
|
||||
'else_blocks' => $else_blocks,
|
||||
),
|
||||
$sub_v
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* s5 'FOR' '(' Var 'IN' Var ')' '{' Script '}' */
|
||||
|
||||
function xFORBlock($v) {
|
||||
if ($r = $this->x("FOR\s*\(\s*[\$\?]([^\s]+)\s+IN\s+[\$\?]([^\s]+)\s*\)", $v)) {/* @@todo split into sub-patterns? */
|
||||
$iterator = $r[1];
|
||||
$set_var = $r[2];
|
||||
$sub_v = $r[3];
|
||||
if ((list($sub_r, $sub_v) = $this->xBlockSet($sub_v)) && $sub_r) {
|
||||
return array(
|
||||
array(
|
||||
'type' => 'forblock',
|
||||
'set' => $set_var,
|
||||
'iterator' => $iterator,
|
||||
'blocks' => $sub_r['blocks']
|
||||
),
|
||||
$sub_v
|
||||
);
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
/* s6 Var '+' Var */
|
||||
|
||||
function xVarMerge($v) {
|
||||
if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
|
||||
$var1 = $sub_r;
|
||||
if ($sub_r = $this->x("\+", $sub_v)) {
|
||||
$sub_v = $sub_r[1];
|
||||
if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
|
||||
return array(
|
||||
array($var1, $sub_r),
|
||||
$sub_v
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array(0, $v);
|
||||
}
|
||||
|
||||
}
|
||||
581
arc/sparqlscript/ARC2_SPARQLScriptProcessor.php
Normal file
581
arc/sparqlscript/ARC2_SPARQLScriptProcessor.php
Normal file
@@ -0,0 +1,581 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: ARC or plugin homepage
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 SPARQLScript Processor
|
||||
author:
|
||||
version: 2009-07-09 (Tweak: improved PREFIX injection)
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_SPARQLScriptProcessor extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_SPARQLScriptProcessor ($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->max_operations = $this->v('sparqlscript_max_operations', 0, $this->a);
|
||||
$this->max_queries = $this->v('sparqlscript_max_queries', 0, $this->a);
|
||||
$this->return = 0;
|
||||
$this->script_hash = '';
|
||||
$this->env = array(
|
||||
'endpoint' => '',
|
||||
'vars' => array(),
|
||||
'output' => '',
|
||||
'operation_count' => 0,
|
||||
'query_count' => 0,
|
||||
'query_log' => array()
|
||||
);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
$this->__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processScript($s) {
|
||||
$this->script_hash = abs(crc32($s));
|
||||
$parser = $this->getParser();
|
||||
$parser->parse($s);
|
||||
$blocks = $parser->getScriptBlocks();
|
||||
if ($parser->getErrors()) return 0;
|
||||
foreach ($blocks as $block) {
|
||||
$this->processBlock($block);
|
||||
if ($this->return) return 0;
|
||||
if ($this->getErrors()) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function getResult() {
|
||||
if ($this->return) {
|
||||
return $this->getVarValue('__return_value__');
|
||||
}
|
||||
else {
|
||||
return $this->env['output'];
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getParser() {
|
||||
ARC2::inc('SPARQLScriptParser');
|
||||
return new ARC2_SPARQLScriptParser($this->a, $this);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function setVar($name, $val, $type = 'literal', $meta = '') {
|
||||
/* types: literal, var, rows, bool, doc, http_response, undefined, ? */
|
||||
$this->env['vars'][$name] = array(
|
||||
'value_type' => $type,
|
||||
'value' => $val,
|
||||
'meta' => $meta ? $meta : array()
|
||||
);
|
||||
}
|
||||
|
||||
function getVar($name) {
|
||||
return isset($this->env['vars'][$name]) ? $this->env['vars'][$name] : '';
|
||||
}
|
||||
|
||||
function getVarValue($name) {
|
||||
return ($v = $this->getVar($name)) ? (isset($v['value']) ? $v['value'] : $v ) : '';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function replacePlaceholders($val, $context = '', $return_string = 1, $loop = 0) {
|
||||
do {
|
||||
$old_val = $val;
|
||||
if (preg_match_all('/(\{(?:[^{}]+|(?R))*\})/', $val, $m)) {
|
||||
foreach ($m[1] as $match) {
|
||||
if (strpos($val, '$' . $match) === false) {/* just some container brackets, recurse */
|
||||
$val = str_replace($match, '{' . $this->replacePlaceholders(substr($match, 1, -1), $context, $return_string, $loop + 1) . '}', $val);
|
||||
}
|
||||
else {
|
||||
$ph = substr($match, 1, -1);
|
||||
$sub_val = $this->getPlaceholderValue($ph);
|
||||
if (is_array($sub_val)) {
|
||||
$sub_val = $this->getArraySerialization($sub_val, $context);
|
||||
}
|
||||
$val = str_replace('${' . $ph . '}', $sub_val, $val);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (($old_val != $val) && ($loop < 10));
|
||||
return $val;
|
||||
}
|
||||
|
||||
function getPlaceholderValue($ph) {
|
||||
/* simple vars */
|
||||
if (isset($this->env['vars'][$ph])) {
|
||||
return $this->v('value', $this->env['vars'][$ph], $this->env['vars'][$ph]);
|
||||
}
|
||||
/* GET/POST */
|
||||
if (preg_match('/^(GET|POST)\.([^\.]+)(.*)$/', $ph, $m)) {
|
||||
$vals = strtoupper($m[1]) == 'GET' ? $_GET : $POST;
|
||||
$r = isset($vals[$m[2]]) ? $vals[$m[2]] : '';
|
||||
return $m[3] ? $this->getPropertyValue(array('value' => $r, 'value_type' => '?'), ltrim($m[3], '.')) : $r;
|
||||
}
|
||||
/* NOW */
|
||||
if (preg_match('/^NOW(.*)$/', $ph, $m)) {
|
||||
$rest = $m[1];
|
||||
/* may have sub-phs */
|
||||
$rest = $this->replacePlaceholders($rest);
|
||||
$r_struct = array(
|
||||
'y' => date('Y'),
|
||||
'mo' => date('m'),
|
||||
'd' => date('d'),
|
||||
'h' => date('H'),
|
||||
'mi' => date('i'),
|
||||
's' => date('s')
|
||||
);
|
||||
if (preg_match('/(\+|\-)\s*([0-9]+)(y|mo|d|h|mi|s)[a-z]*(.*)/is', trim($rest), $m2)) {
|
||||
eval('$r_struct[$m2[3]] ' . $m2[1] . '= (int)' . $m2[2] . ';');
|
||||
$rest = $m2[4];
|
||||
}
|
||||
$uts = mktime($r_struct['h'], $r_struct['mi'], $r_struct['s'], $r_struct['mo'], $r_struct['d'], $r_struct['y']);
|
||||
$uts -= date('Z', $uts); /* timezone offset */
|
||||
$r = date('Y-m-d\TH:i:s\Z', $uts);
|
||||
if (preg_match('/^\.(.+)$/', $rest, $m)) {
|
||||
return $this->getPropertyValue(array('value' => $r), $m[1]);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
/* property */
|
||||
if (preg_match('/^([^\.]+)\.(.+)$/', $ph, $m)) {
|
||||
list($var, $path) = array($m[1], $m[2]);
|
||||
if (isset($this->env['vars'][$var])) {
|
||||
return $this->getPropertyValue($this->env['vars'][$var], $path);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function getPropertyValue($obj, $path) {
|
||||
$val = isset($obj['value']) ? $obj['value'] : $obj;
|
||||
$path = $this->replacePlaceholders($path, 'property_value', 0);
|
||||
/* reserved */
|
||||
if ($path == 'size') {
|
||||
if ($obj['value_type'] == 'rows') return count($val);
|
||||
if ($obj['value_type'] == 'literal') return strlen($val);
|
||||
}
|
||||
if (preg_match('/^replace\([\'\"](\/.*\/[a-z]*)[\'\"],\s*[\'\"](.*)[\'\"]\)$/is', $path, $m)) {
|
||||
return @preg_replace($m[1], str_replace('$', '\\', $m[2]), $val);
|
||||
}
|
||||
if (preg_match('/^match\([\'\"](\/.*\/[a-z]*)[\'\"]\)$/is', $path, $m)) {
|
||||
return @preg_match($m[1], $val, $m) ? $m : '';
|
||||
}
|
||||
if (preg_match('/^urlencode\([\'\"]?(get|post|.*)[\'\"]?\)$/is', $path, $m)) {
|
||||
return (strtolower($m[1]) == 'post') ? rawurlencode($val) : urlencode($val);
|
||||
}
|
||||
if (preg_match('/^toDataURI\([^\)]*\)$/is', $path, $m)) {
|
||||
return 'data:text/plain;charset=utf-8,' . rawurlencode($val);
|
||||
}
|
||||
if (preg_match('/^fromDataURI\([^\)]*\)$/is', $path, $m)) {
|
||||
return rawurldecode(str_replace('data:text/plain;charset=utf-8,', '', $val));
|
||||
}
|
||||
if (preg_match('/^toPrettyDate\([^\)]*\)$/is', $path, $m)) {
|
||||
$uts = strtotime(preg_replace('/(T|\+00\:00)/', ' ', $val));
|
||||
return date('D j M H:i', $uts);
|
||||
}
|
||||
if (preg_match('/^render\(([^\)]*)\)$/is', $path, $m)) {
|
||||
$src_format = trim($m[1], '"\'');
|
||||
return $this->render($val, $src_format);
|
||||
}
|
||||
/* struct */
|
||||
if (is_array($val)) {
|
||||
if (isset($val[$path])) return $val[$path];
|
||||
$exp_path = $this->expandPName($path);
|
||||
if (isset($val[$exp_path])) return $val[$exp_path];
|
||||
if (preg_match('/^([^\.]+)\.(.+)$/', $path, $m)) {
|
||||
list($var, $path) = array($m[1], $m[2]);
|
||||
if (isset($val[$var])) {
|
||||
return $this->getPropertyValue(array('value' => $val[$var]), $path);
|
||||
}
|
||||
/* qname */
|
||||
$exp_var = $this->expandPName($var);
|
||||
if (isset($val[$exp_var])) {
|
||||
return $this->getPropertyValue(array('value' => $val[$exp_var]), $path);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
/* meta */
|
||||
if (preg_match('/^\_/', $path) && isset($obj['meta']) && isset($obj['meta'][substr($path, 1)])) {
|
||||
return $obj['meta'][substr($path, 1)];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function render($val, $src_format = '') {
|
||||
if ($src_format) {
|
||||
$mthd = 'render' . $this->camelCase($src_format);
|
||||
if (method_exists($this, $mthd)) {
|
||||
return $this->$mthd($val);
|
||||
}
|
||||
else {
|
||||
return 'No rendering method found for "' . $src_format. '"';
|
||||
}
|
||||
}
|
||||
/* try RDF */
|
||||
return $this->getArraySerialization($val);
|
||||
}
|
||||
|
||||
function renderObjects($os) {
|
||||
$r = '';
|
||||
foreach ($os as $o) {
|
||||
$r .= $r ? ', ' : '';
|
||||
$r .= $o['value'];
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getArraySerialization($v, $context) {
|
||||
$v_type = ARC2::getStructType($v);/* string|array|triples|index */
|
||||
$pf = ARC2::getPreferredFormat();
|
||||
/* string */
|
||||
if ($v_type == 'string') return $v;
|
||||
/* simple array (e.g. from SELECT) */
|
||||
if ($v_type == 'array') {
|
||||
$m = method_exists($this, 'toLegacy' . $pf) ? 'toLegacy' . $pf : 'toLegacyXML';
|
||||
}
|
||||
/* rdf */
|
||||
if (($v_type == 'triples') || ($v_type == 'index')) {
|
||||
$m = method_exists($this, 'to' . $pf) ? 'to' . $pf : ($context == 'query' ? 'toNTriples' : 'toRDFXML');
|
||||
}
|
||||
/* else */
|
||||
return $this->$m($v);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processBlock($block) {
|
||||
if ($this->max_operations && ($this->env['operation_count'] >= $this->max_operations)) return $this->addError('Number of ' . $this->max_operations . ' allowed operations exceeded.');
|
||||
if ($this->return) return 0;
|
||||
$this->env['operation_count']++;
|
||||
$type = $block['type'];
|
||||
$m = 'process' . $this->camelCase($type) . 'Block';
|
||||
if (method_exists($this, $m)) {
|
||||
return $this->$m($block);
|
||||
}
|
||||
return $this->addError('Unsupported block type "' . $type . '"');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processEndpointDeclBlock($block) {
|
||||
$this->env['endpoint'] = $block['endpoint'];
|
||||
return $this->env;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processQueryBlock($block) {
|
||||
if ($this->max_queries && ($this->env['query_count'] >= $this->max_queries)) return $this->addError('Number of ' . $this->max_queries . ' allowed queries exceeded.');
|
||||
$this->env['query_count']++;
|
||||
$ep_uri = $this->replacePlaceholders($this->env['endpoint'], 'endpoint');
|
||||
/* q */
|
||||
$prologue = 'BASE <' . $block['base']. '>';
|
||||
$q = $this->replacePlaceholders($block['query'], 'query');
|
||||
/* prefixes */
|
||||
$ns = isset($this->a['ns']) ? array_merge($this->a['ns'], $block['prefixes']) : $block['prefixes'];
|
||||
$q = $prologue . "\n" . $this->completeQuery($q, $ns);
|
||||
$this->env['query_log'][] = '(' . $ep_uri . ') ' . $q;
|
||||
if ($store = $this->getStore($ep_uri)) {
|
||||
$sub_r = $this->v('is_remote', '', $store) ? $store->query($q, '', $ep_uri) : $store->query($q);
|
||||
/* ignore socket errors */
|
||||
if (($errs = $this->getErrors()) && preg_match('/socket/', $errs[0])) {
|
||||
$this->warnings[] = $errs[0];
|
||||
$this->errors = array();
|
||||
$sub_r = array();
|
||||
}
|
||||
return $sub_r;
|
||||
}
|
||||
else {
|
||||
return $this->addError("no store (" . $ep_uri . ")");
|
||||
}
|
||||
}
|
||||
|
||||
function getStore($ep_uri) {
|
||||
/* local store */
|
||||
if ((!$ep_uri || $ep_uri == ARC2::getScriptURI()) && ($this->v('sparqlscript_default_endpoint', '', $this->a) == 'local')) {
|
||||
if (!isset($this->local_store)) $this->local_store = ARC2::getStore($this->a);/* @@todo error checking */
|
||||
return $this->local_store;
|
||||
}
|
||||
elseif ($ep_uri) {
|
||||
ARC2::inc('RemoteStore');
|
||||
$conf = array_merge($this->a, array('remote_store_endpoint' => $ep_uri, 'reader_timeout' => 10));
|
||||
return new ARC2_RemoteStore($conf, $this);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processAssignmentBlock($block) {
|
||||
$sub_type = $block['sub_type'];
|
||||
$m = 'process' . $this->camelCase($sub_type) . 'AssignmentBlock';
|
||||
if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"');
|
||||
return $this->$m($block);
|
||||
}
|
||||
|
||||
function processQueryAssignmentBlock($block) {
|
||||
$qr = $this->processQueryBlock($block['query']);
|
||||
if ($this->getErrors() || !isset($qr['query_type'])) return 0;
|
||||
$qt = $qr['query_type'];
|
||||
$vts = array('ask' => 'bool', 'select' => 'rows', 'desribe' => 'doc', 'construct' => 'doc');
|
||||
$r = array(
|
||||
'value_type' => isset($vts[$qt]) ? $vts[$qt] : $qt . ' result',
|
||||
'value' => ($qt == 'select') ? $this->v('rows', array(), $qr['result']) : $qr['result'],
|
||||
);
|
||||
$this->env['vars'][$block['var']['value']] = $r;
|
||||
}
|
||||
|
||||
function processStringAssignmentBlock($block) {
|
||||
$r = array('value_type' => 'literal', 'value' => $this->replacePlaceholders($block['string']['value']));
|
||||
$this->env['vars'][$block['var']['value']] = $r;
|
||||
}
|
||||
|
||||
function processVarAssignmentBlock($block) {
|
||||
if (isset($this->env['vars'][$block['var2']['value']])) {
|
||||
$this->env['vars'][$block['var']['value']] = $this->env['vars'][$block['var2']['value']];
|
||||
}
|
||||
else {
|
||||
$this->env['vars'][$block['var']['value']] = array('value_type' => 'undefined', 'value' => '');
|
||||
}
|
||||
}
|
||||
|
||||
function processPlaceholderAssignmentBlock($block) {
|
||||
$ph_val = $this->getPlaceholderValue($block['placeholder']['value']);
|
||||
$this->env['vars'][$block['var']['value']] = array('value_type' => 'undefined', 'value' => $ph_val);
|
||||
}
|
||||
|
||||
function processVarMergeAssignmentBlock($block) {
|
||||
$val1 = isset($this->env['vars'][$block['var2']['value']]) ? $this->env['vars'][$block['var2']['value']] : array('value_type' => 'undefined', 'value' => '');
|
||||
$val2 = isset($this->env['vars'][$block['var3']['value']]) ? $this->env['vars'][$block['var3']['value']] : array('value_type' => 'undefined', 'value' => '');
|
||||
if (is_array($val1) && is_array($val2)) {
|
||||
$this->env['vars'][$block['var']['value']] = array('value_type' => $val2['value_type'], 'value' => array_merge($val1['value'], $val2['value']));
|
||||
}
|
||||
elseif (is_numeric($val1) && is_numeric($val2)) {
|
||||
$this->env['vars'][$block['var']['value']] = $val1 + $val2;
|
||||
}
|
||||
}
|
||||
|
||||
function processFunctionCallAssignmentBlock($block) {
|
||||
$sub_r = $this->processFunctionCallBlock($block['function_call']);
|
||||
if ($this->getErrors()) return 0;
|
||||
$this->env['vars'][$block['var']['value']] = $sub_r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processReturnBlock($block) {
|
||||
$sub_type = $block['sub_type'];
|
||||
$m = 'process' . $this->camelCase($sub_type) . 'AssignmentBlock';
|
||||
if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"');
|
||||
$sub_r = $this->$m($block);
|
||||
$this->return = 1;
|
||||
return $sub_r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processIfblockBlock($block) {
|
||||
if ($this->testCondition($block['condition'])) {
|
||||
$blocks = $block['blocks'];
|
||||
}
|
||||
else {
|
||||
$blocks = $block['else_blocks'];
|
||||
}
|
||||
foreach ($blocks as $block) {
|
||||
$sub_r = $this->processBlock($block);
|
||||
if ($this->getErrors()) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function testCondition($cond) {
|
||||
$m = 'test' . $this->camelCase($cond['type']) . 'Condition';
|
||||
if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"');
|
||||
return $this->$m($cond);
|
||||
}
|
||||
|
||||
function testVarCondition($cond) {
|
||||
$r = 0;
|
||||
$vn = $cond['value'];
|
||||
if (isset($this->env['vars'][$vn])) $r = $this->env['vars'][$vn]['value'];
|
||||
$op = $this->v('operator', '', $cond);
|
||||
if ($op == '!') $r = !$r;
|
||||
return $r ? true : false;
|
||||
}
|
||||
|
||||
function testPlaceholderCondition($cond) {
|
||||
$val = $this->getPlaceholderValue($cond['value']);
|
||||
$r = $val ? true : false;
|
||||
$op = $this->v('operator', '', $cond);
|
||||
if ($op == '!') $r = !$r;
|
||||
return $r;
|
||||
}
|
||||
|
||||
function testExpressionCondition($cond) {
|
||||
$m = 'test' . $this->camelCase($cond['sub_type']) . 'ExpressionCondition';
|
||||
if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"');
|
||||
return $this->$m($cond);
|
||||
}
|
||||
|
||||
function testRelationalExpressionCondition($cond) {
|
||||
$op = $cond['operator'];
|
||||
if ($op == '=') $op = '==';
|
||||
$val1 = $this->getPatternValue($cond['patterns'][0]);
|
||||
$val2 = $this->getPatternValue($cond['patterns'][1]);
|
||||
eval('$result = ($val1 ' . $op . ' $val2) ? 1 : 0;');
|
||||
return $result;
|
||||
}
|
||||
|
||||
function testAndExpressionCondition($cond) {
|
||||
foreach ($cond['patterns'] as $pattern) {
|
||||
if (!$this->testCondition($pattern)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getPatternValue($pattern) {
|
||||
$m = 'get' . $this->camelCase($pattern['type']) . 'PatternValue';
|
||||
if (!method_exists($this, $m)) return '';
|
||||
return $this->$m($pattern);
|
||||
}
|
||||
|
||||
function getLiteralPatternValue($pattern) {
|
||||
return $pattern['value'];
|
||||
}
|
||||
|
||||
function getPlaceholderPatternValue($pattern) {
|
||||
return $this->getPlaceholderValue($pattern['value']);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processForblockBlock($block) {
|
||||
$set = $this->v($block['set'], array('value' => array()), $this->env['vars']);
|
||||
$entries = isset($set['value']) ? $set['value'] : $set;
|
||||
$iterator = $block['iterator'];
|
||||
$blocks = $block['blocks'];
|
||||
if (!is_array($entries)) return 0;
|
||||
$rc = count($entries);
|
||||
foreach ($entries as $i => $entry) {
|
||||
$val_type = $this->v('value_type', 'set', $set) . ' entry';
|
||||
$this->env['vars'][$iterator] = array(
|
||||
'value' => $entry,
|
||||
'value_type' => $val_type,
|
||||
'meta' => array(
|
||||
'pos' => $i,
|
||||
'odd_even' => ($i % 2) ? 'even' : 'odd'
|
||||
)
|
||||
);
|
||||
foreach ($blocks as $block) {
|
||||
$this->processBlock($block);
|
||||
if ($this->getErrors()) return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processLiteralBlock($block) {
|
||||
$this->env['output'] .= $this->replacePlaceholders($block['value'], 'output');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processFunctionCallBlock($block) {
|
||||
$uri = $this->replacePlaceholders($block['uri'], 'function_call');
|
||||
/* built-ins */
|
||||
if (strpos($uri, $this->a['ns']['sps']) === 0) {
|
||||
return $this->processBuiltinFunctionCallBlock($block);
|
||||
}
|
||||
/* remote functions */
|
||||
}
|
||||
|
||||
function processBuiltinFunctionCallBlock($block) {
|
||||
$fnc_uri = $this->replacePlaceholders($block['uri'], 'function_call');
|
||||
$fnc_name = substr($fnc_uri, strlen($this->a['ns']['sps']));
|
||||
if (preg_match('/^(get|post)$/i', $fnc_name, $m)) {
|
||||
return $this->processHTTPCall($block, strtoupper($m[1]));
|
||||
}
|
||||
}
|
||||
|
||||
function processHTTPCall($block, $mthd = 'GET') {
|
||||
ARC2::inc('Reader');
|
||||
$reader =& new ARC2_Reader($this->a, $this);
|
||||
$url = $this->replacePlaceholders($block['args'][0]['value'], 'function_call');
|
||||
if ($mthd != 'GET') {
|
||||
$reader->setHTTPMethod($mthd);
|
||||
$reader->setCustomHeaders("Content-Type: application/x-www-form-urlencoded");
|
||||
}
|
||||
$to = $this->v('remote_call_timeout', 0, $this->a);
|
||||
$reader->activate($url, '', 0, $to);
|
||||
$format = $reader->getFormat();
|
||||
$resp = '';
|
||||
while ($d = $reader->readStream()) {
|
||||
$resp .= $d;
|
||||
}
|
||||
$reader->closeStream();
|
||||
unset($this->reader);
|
||||
return array('value_type' => 'http_response', 'value' => $resp);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extractVars($pattern, $input = '') {
|
||||
$vars = array();
|
||||
/* replace PHs, track ()s */
|
||||
$regex = $pattern;
|
||||
$vars = array();
|
||||
if (preg_match_all('/([\?\$]\{([^\}]+)\}|\([^\)]+\))/', $regex, $m)) {
|
||||
$matches = $m[1];
|
||||
$pre_vars = $m[2];
|
||||
foreach ($matches as $i => $match) {
|
||||
$vars[] = $pre_vars[$i];
|
||||
if ($pre_vars[$i]) {/* placeholder */
|
||||
$regex = str_replace($match, '(.+)', $regex);
|
||||
}
|
||||
else {/* parentheses, but may contain placeholders */
|
||||
$sub_regex = $match;
|
||||
while (preg_match('/([\?\$]\{([^\}]+)\})/', $sub_regex, $m)) {
|
||||
$sub_regex = str_replace($m[1], '(.+)', $sub_regex);
|
||||
$vars[] = $m[2];
|
||||
}
|
||||
$regex = str_replace($match, $sub_regex, $regex);
|
||||
}
|
||||
}
|
||||
/* eval regex */
|
||||
if (@preg_match('/' . $regex . '/is', $input, $m)) {
|
||||
$vals = $m;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
for ($i = 0; $i < count($vars); $i++) {
|
||||
if ($vars[$i]) {
|
||||
$this->setVar($vars[$i], isset($vals[$i + 1]) ? $vals[$i + 1] : '');
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/* no placeholders */
|
||||
return ($pattern == $input) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
198
arc/store/ARC2_MemStore.php
Normal file
198
arc/store/ARC2_MemStore.php
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 Memory Store
|
||||
*
|
||||
* @author Benjamin Nowack <bnowack@semsol.com>
|
||||
* @license http://arc.semsol.org/license
|
||||
* @package ARC2
|
||||
* @version 2009-08-13
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_MemStore extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_MemStore($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
$this->is_mem = 1;
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->data = array();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function isSetUp() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
function setUp() {}
|
||||
|
||||
/* */
|
||||
|
||||
function reset() {
|
||||
$this->data = array();
|
||||
}
|
||||
|
||||
function drop() {
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function insert($doc, $g = 'http://localhost/') {
|
||||
$index = $this->v($g, array(), $this->data);
|
||||
$this->data[$g] = ARC2::getMergedIndex($index, $this->toIndex($doc));
|
||||
}
|
||||
|
||||
/* */
|
||||
/* */
|
||||
|
||||
|
||||
function delete($doc, $g = 'http://localhost/') {
|
||||
$index = $this->v($g, array(), $this->data);
|
||||
$this->data[$g] = ARC2::getCleanedIndex($index, $this->toIndex($doc));
|
||||
}
|
||||
|
||||
function replace($doc, $g, $doc_2) {
|
||||
return array($this->delete($doc, $g), $this->insert($doc_2, $g));
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0) {
|
||||
if ($log_query) $this->logQuery($q);
|
||||
ARC2::inc('SPARQLPlusParser');
|
||||
$p = & new ARC2_SPARQLPlusParser($this->a, $this);
|
||||
$p->parse($q, $src);
|
||||
$infos = $p->getQueryInfos();
|
||||
$t1 = ARC2::mtime();
|
||||
if (!$errs = $p->getErrors()) {
|
||||
$qt = $infos['query']['type'];
|
||||
$r = array('query_type' => $qt, 'result' => $this->runQuery($q, $qt));
|
||||
}
|
||||
else {
|
||||
$r = array('result' => '');
|
||||
}
|
||||
$t2 = ARC2::mtime();
|
||||
$r['query_time'] = $t2 - $t1;
|
||||
/* query result */
|
||||
if ($result_format == 'raw') {
|
||||
return $r['result'];
|
||||
}
|
||||
if ($result_format == 'rows') {
|
||||
return $this->v('rows', array(), $r['result']);
|
||||
}
|
||||
if ($result_format == 'row') {
|
||||
return $r['result']['rows'] ? $r['result']['rows'][0] : array();
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function runQuery($q, $qt = '') {
|
||||
/* ep */
|
||||
$ep = $this->v('remote_store_endpoint', 0, $this->a);
|
||||
if (!$ep) return false;
|
||||
/* prefixes */
|
||||
$ns = isset($this->a['ns']) ? $this->a['ns'] : array();
|
||||
$added_prefixes = array();
|
||||
$prologue = '';
|
||||
foreach ($ns as $k => $v) {
|
||||
$k = rtrim($k, ':');
|
||||
if (in_array($k, $added_prefixes)) continue;
|
||||
if (preg_match('/(^|\s)' . $k . ':/s', $q) && !preg_match('/PREFIX\s+' . $k . '\:/is', $q)) {
|
||||
$prologue .= "\n" . 'PREFIX ' . $k . ': <' . $v . '>';
|
||||
}
|
||||
$added_prefixes[] = $k;
|
||||
}
|
||||
$q = $prologue . "\n" . $q;
|
||||
/* http verb */
|
||||
$mthd = in_array($qt, array('load', 'insert', 'delete')) ? 'POST' : 'GET';
|
||||
/* reader */
|
||||
ARC2::inc('Reader');
|
||||
$reader =& new ARC2_Reader($this->a, $this);
|
||||
$reader->setAcceptHeader('Accept: application/sparql-results+xml; q=0.9, application/rdf+xml; q=0.9, */*; q=0.1');
|
||||
if ($mthd == 'GET') {
|
||||
$url = $ep;
|
||||
$url .= strpos($ep, '?') ? '&' : '?';
|
||||
$url .= 'query=' . urlencode($q);
|
||||
if ($k = $this->v('store_read_key', '', $this->a)) $url .= '&key=' . urlencode($k);
|
||||
}
|
||||
else {
|
||||
$url = $ep;
|
||||
$reader->setHTTPMethod($mthd);
|
||||
$reader->setCustomHeaders("Content-Type: application/x-www-form-urlencoded");
|
||||
$suffix = ($k = $this->v('store_write_key', '', $this->a)) ? '&key=' . rawurlencode($k) : '';
|
||||
$reader->setMessageBody('query=' . rawurlencode($q) . $suffix);
|
||||
}
|
||||
$to = $this->v('remote_store_timeout', 0, $this->a);
|
||||
$reader->activate($url, '', 0, $to);
|
||||
$format = $reader->getFormat();
|
||||
$resp = '';
|
||||
while ($d = $reader->readStream()) {
|
||||
$resp .= $d;
|
||||
}
|
||||
$reader->closeStream();
|
||||
$ers = $reader->getErrors();
|
||||
unset($this->reader);
|
||||
if ($ers) return array('errors' => $ers);
|
||||
$mappings = array('rdfxml' => 'RDFXML', 'sparqlxml' => 'SPARQLXMLResult', 'turtle' => 'Turtle');
|
||||
if (!$format || !isset($mappings[$format])) {
|
||||
return $resp;
|
||||
//return $this->addError('No parser available for "' . $format . '" SPARQL result');
|
||||
}
|
||||
/* format parser */
|
||||
$suffix = $mappings[$format] . 'Parser';
|
||||
ARC2::inc($suffix);
|
||||
$cls = 'ARC2_' . $suffix;
|
||||
$parser =& new $cls($this->a, $this);
|
||||
$parser->parse($ep, $resp);
|
||||
/* ask|load|insert|delete */
|
||||
if (in_array($qt, array('ask', 'load', 'insert', 'delete'))) {
|
||||
$bid = $parser->getBooleanInsertedDeleted();
|
||||
switch ($qt) {
|
||||
case 'ask': return $bid['boolean'];
|
||||
default: return $bid;
|
||||
}
|
||||
}
|
||||
/* select */
|
||||
if (($qt == 'select') && !method_exists($parser, 'getRows')) return $resp;
|
||||
if ($qt == 'select') return array('rows' => $parser->getRows(), 'variables' => $parser->getVariables());
|
||||
/* any other */
|
||||
return $parser->getSimpleIndex(0);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function optimizeTables() {}
|
||||
|
||||
/* */
|
||||
|
||||
function getResourceLabel($res, $unnamed_label = 'An unnamed resource') {
|
||||
if (!isset($this->resource_labels)) $this->resource_labels = array();
|
||||
if (isset($this->resource_labels[$res])) return $this->resource_labels[$res];
|
||||
if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) return $res;/* literal */
|
||||
$r = '';
|
||||
if (preg_match('/^\_\:/', $res)) {
|
||||
return $unnamed_label;
|
||||
}
|
||||
$row = $this->query('SELECT ?o WHERE { <' . $res . '> ?p ?o . FILTER(REGEX(str(?p), "(label|name)$", "i"))}', 'row');
|
||||
if ($row) {
|
||||
$r = $row['o'];
|
||||
}
|
||||
else {
|
||||
$r = preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
|
||||
$r = str_replace('_', ' ', $r);
|
||||
$r = preg_replace('/([a-z])([A-Z])/e', '"\\1 " . strtolower("\\2")', $r);
|
||||
}
|
||||
$this->resource_labels[$res] = $r;
|
||||
return $r;
|
||||
}
|
||||
|
||||
}
|
||||
196
arc/store/ARC2_RemoteStore.php
Normal file
196
arc/store/ARC2_RemoteStore.php
Normal file
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 Remote RDF Store
|
||||
*
|
||||
* @author Benjamin Nowack <bnowack@semsol.com>
|
||||
* @license http://arc.semsol.org/license
|
||||
* @package ARC2
|
||||
* @version 2009-12-08
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_RemoteStore extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_RemoteStore($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
$this->is_remote = 1;
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function isSetUp() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
function setUp() {}
|
||||
|
||||
/* */
|
||||
|
||||
function reset() {}
|
||||
|
||||
function drop() {}
|
||||
|
||||
function insert($doc, $g, $keep_bnode_ids = 0) {
|
||||
return $this->query('INSERT INTO <' . $g . '> { ' . $this->toNTriples($doc, '', 1) . ' }');
|
||||
}
|
||||
|
||||
function delete($doc, $g) {
|
||||
if (!$doc) {
|
||||
return $this->query('DELETE FROM <' . $g . '>');
|
||||
}
|
||||
else {
|
||||
return $this->query('DELETE FROM <' . $g . '> { ' . $this->toNTriples($doc, '', 1) . ' }');
|
||||
}
|
||||
}
|
||||
|
||||
function replace($doc, $g, $doc_2) {
|
||||
return array($this->delete($doc, $g), $this->insert($doc_2, $g));
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0) {
|
||||
if ($log_query) $this->logQuery($q);
|
||||
ARC2::inc('SPARQLPlusParser');
|
||||
$p = & new ARC2_SPARQLPlusParser($this->a, $this);
|
||||
$p->parse($q, $src);
|
||||
$infos = $p->getQueryInfos();
|
||||
$t1 = ARC2::mtime();
|
||||
if (!$errs = $p->getErrors()) {
|
||||
$qt = $infos['query']['type'];
|
||||
$r = array('query_type' => $qt, 'result' => $this->runQuery($q, $qt, $infos));
|
||||
}
|
||||
else {
|
||||
$r = array('result' => '');
|
||||
}
|
||||
$t2 = ARC2::mtime();
|
||||
$r['query_time'] = $t2 - $t1;
|
||||
/* query result */
|
||||
if ($result_format == 'raw') {
|
||||
return $r['result'];
|
||||
}
|
||||
if ($result_format == 'rows') {
|
||||
return $this->v('rows', array(), $r['result']);
|
||||
}
|
||||
if ($result_format == 'row') {
|
||||
if (!isset($r['result']['rows'])) return array();
|
||||
return $r['result']['rows'] ? $r['result']['rows'][0] : array();
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function runQuery($q, $qt = '', $infos = '') {
|
||||
/* ep */
|
||||
$ep = $this->v('remote_store_endpoint', 0, $this->a);
|
||||
if (!$ep) return false;
|
||||
/* prefixes */
|
||||
$q = $this->completeQuery($q);
|
||||
/* custom handling */
|
||||
$mthd = 'run' . $this->camelCase($qt) . 'Query';
|
||||
if (method_exists($this, $mthd)) {
|
||||
return $this->$mthd($q, $infos);
|
||||
}
|
||||
/* http verb */
|
||||
$mthd = in_array($qt, array('load', 'insert', 'delete')) ? 'POST' : 'GET';
|
||||
/* reader */
|
||||
ARC2::inc('Reader');
|
||||
$reader =& new ARC2_Reader($this->a, $this);
|
||||
$reader->setAcceptHeader('Accept: application/sparql-results+xml; q=0.9, application/rdf+xml; q=0.9, */*; q=0.1');
|
||||
if ($mthd == 'GET') {
|
||||
$url = $ep;
|
||||
$url .= strpos($ep, '?') ? '&' : '?';
|
||||
$url .= 'query=' . urlencode($q);
|
||||
if ($k = $this->v('store_read_key', '', $this->a)) $url .= '&key=' . urlencode($k);
|
||||
}
|
||||
else {
|
||||
$url = $ep;
|
||||
$reader->setHTTPMethod($mthd);
|
||||
$reader->setCustomHeaders("Content-Type: application/x-www-form-urlencoded");
|
||||
$suffix = ($k = $this->v('store_write_key', '', $this->a)) ? '&key=' . rawurlencode($k) : '';
|
||||
$reader->setMessageBody('query=' . rawurlencode($q) . $suffix);
|
||||
}
|
||||
$to = $this->v('remote_store_timeout', 0, $this->a);
|
||||
$reader->activate($url, '', 0, $to);
|
||||
$format = $reader->getFormat();
|
||||
$resp = '';
|
||||
while ($d = $reader->readStream()) {
|
||||
$resp .= $d;
|
||||
}
|
||||
$reader->closeStream();
|
||||
$ers = $reader->getErrors();
|
||||
$this->a['reader_auth_infos'] = $reader->getAuthInfos();
|
||||
unset($this->reader);
|
||||
if ($ers) return array('errors' => $ers);
|
||||
$mappings = array('rdfxml' => 'RDFXML', 'sparqlxml' => 'SPARQLXMLResult', 'turtle' => 'Turtle');
|
||||
if (!$format || !isset($mappings[$format])) {
|
||||
return $resp;
|
||||
//return $this->addError('No parser available for "' . $format . '" SPARQL result');
|
||||
}
|
||||
/* format parser */
|
||||
$suffix = $mappings[$format] . 'Parser';
|
||||
ARC2::inc($suffix);
|
||||
$cls = 'ARC2_' . $suffix;
|
||||
$parser =& new $cls($this->a, $this);
|
||||
$parser->parse($ep, $resp);
|
||||
/* ask|load|insert|delete */
|
||||
if (in_array($qt, array('ask', 'load', 'insert', 'delete'))) {
|
||||
$bid = $parser->getBooleanInsertedDeleted();
|
||||
switch ($qt) {
|
||||
case 'ask': return $bid['boolean'];
|
||||
default: return $bid;
|
||||
}
|
||||
}
|
||||
/* select */
|
||||
if (($qt == 'select') && !method_exists($parser, 'getRows')) return $resp;
|
||||
if ($qt == 'select') return array('rows' => $parser->getRows(), 'variables' => $parser->getVariables());
|
||||
/* any other */
|
||||
return $parser->getSimpleIndex(0);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function optimizeTables() {}
|
||||
|
||||
/* */
|
||||
|
||||
function getResourceLabel($res, $unnamed_label = 'An unnamed resource') {
|
||||
if (!isset($this->resource_labels)) $this->resource_labels = array();
|
||||
if (isset($this->resource_labels[$res])) return $this->resource_labels[$res];
|
||||
if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) return $res;/* literal */
|
||||
$r = '';
|
||||
if (preg_match('/^\_\:/', $res)) {
|
||||
return $unnamed_label;
|
||||
}
|
||||
$row = $this->query('SELECT ?o WHERE { <' . $res . '> ?p ?o . FILTER(REGEX(str(?p), "(label|name)$", "i"))}', 'row');
|
||||
if ($row) {
|
||||
$r = $row['o'];
|
||||
}
|
||||
else {
|
||||
$r = preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
|
||||
$r = str_replace('_', ' ', $r);
|
||||
$r = preg_replace('/([a-z])([A-Z])/e', '"\\1 " . strtolower("\\2")', $r);
|
||||
}
|
||||
$this->resource_labels[$res] = $r;
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getDomains($p) {
|
||||
$r = array();
|
||||
foreach($this->query('SELECT DISTINCT ?type WHERE {?s <' . $p . '> ?o ; a ?type . }', 'rows') as $row) {
|
||||
$r[] = $row['type'];
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
584
arc/store/ARC2_Store.php
Normal file
584
arc/store/ARC2_Store.php
Normal file
@@ -0,0 +1,584 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 RDF Store
|
||||
*
|
||||
* @author Benjamin Nowack <bnowack@semsol.com>
|
||||
* @license http://arc.semsol.org/license
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-11-25
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_Store extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_Store($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* db_con */
|
||||
parent::__init();
|
||||
$this->table_lock = 0;
|
||||
$this->triggers = $this->v('store_triggers', array(), $this->a);
|
||||
$this->queue_queries = $this->v('store_queue_queries', 0, $this->a);
|
||||
$this->is_win = (strtolower(substr(PHP_OS, 0, 3)) == 'win') ? true : false;
|
||||
$this->max_split_tables = $this->v('store_max_split_tables', 10, $this->a);
|
||||
$this->split_predicates = $this->v('store_split_predicates', array(), $this->a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getName() {
|
||||
return $this->v('store_name', 'arc', $this->a);
|
||||
}
|
||||
|
||||
function getTablePrefix() {
|
||||
if (!isset($this->tbl_prefix)) {
|
||||
$r = $this->v('db_table_prefix', '', $this->a);
|
||||
$r .= $r ? '_' : '';
|
||||
$r .= $this->getName() . '_';
|
||||
$this->tbl_prefix = $r;
|
||||
}
|
||||
return $this->tbl_prefix;;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function createDBCon() {
|
||||
foreach (array('db_host' => 'localhost', 'db_user' => '', 'db_pwd' => '', 'db_name' => '') as $k => $v) {
|
||||
$this->a[$k] = $this->v($k, $v, $this->a);
|
||||
}
|
||||
if (!$db_con = mysql_connect($this->a['db_host'], $this->a['db_user'], $this->a['db_pwd'])) {
|
||||
return $this->addError(mysql_error());
|
||||
}
|
||||
$this->a['db_con'] =& $db_con;
|
||||
if (!mysql_select_db($this->a['db_name'], $db_con)) {
|
||||
return $this->addError(mysql_error($db_con));
|
||||
}
|
||||
if (preg_match('/^utf8/', $this->getCollation())) {
|
||||
mysql_query("SET NAMES 'utf8'", $db_con);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getDBCon($force = 0) {
|
||||
if ($force || !isset($this->a['db_con'])) {
|
||||
if (!$this->createDBCon()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!$force && !@mysql_thread_id($this->a['db_con'])) return $this->getDBCon(1);
|
||||
return $this->a['db_con'];
|
||||
}
|
||||
|
||||
function closeDBCon() {
|
||||
if ($this->v('db_con', false, $this->a)) {
|
||||
@mysql_close($this->a['db_con']);
|
||||
}
|
||||
unset($this->a['db_con']);
|
||||
}
|
||||
|
||||
function getDBVersion() {
|
||||
if (!$this->v('db_version')) {
|
||||
$this->db_version = preg_match("/^([0-9]+)\.([0-9]+)\.([0-9]+)/", mysql_get_server_info($this->getDBCon()), $m) ? sprintf("%02d-%02d-%02d", $m[1], $m[2], $m[3]) : '00-00-00';
|
||||
}
|
||||
return $this->db_version;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getCollation() {
|
||||
$rs = mysql_query('SHOW TABLE STATUS LIKE "' . $this->getTablePrefix(). 'setting"', $this->getDBCon());
|
||||
return ($rs && ($row = mysql_fetch_array($rs)) && isset($row['Collation'])) ? $row['Collation'] : '';
|
||||
}
|
||||
|
||||
function getColumnType() {
|
||||
if (!$this->v('column_type')) {
|
||||
$tbl = $this->getTablePrefix() . 'g2t';
|
||||
$rs = mysql_query('SHOW COLUMNS FROM ' . $tbl . ' LIKE "t"', $this->getDBCon());
|
||||
$row = $rs ? mysql_fetch_array($rs) : array('Type' => 'mediumint');
|
||||
$this->column_type = preg_match('/mediumint/', $row['Type']) ? 'mediumint' : 'int';
|
||||
}
|
||||
return $this->column_type;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function countDBProcesses() {
|
||||
return ($rs = mysql_query('SHOW PROCESSLIST', $this->getDBCon())) ? mysql_num_rows($rs) : 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTables() {
|
||||
return array('triple', 'g2t', 'id2val', 's2val', 'o2val', 'setting');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function isSetUp() {
|
||||
if ($con = $this->getDBCon()) {
|
||||
$tbl = $this->getTablePrefix() . 'setting';
|
||||
return mysql_query("SELECT 1 FROM " . $tbl . " LIMIT 0", $con) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
function setUp($force = 0) {
|
||||
if (($force || !$this->isSetUp()) && ($con = $this->getDBCon())) {
|
||||
if ($this->getDBVersion() < '04-00-04') {
|
||||
/* UPDATE + JOINs */
|
||||
return $this->addError('MySQL version not supported. ARC requires version 4.0.4 or higher.');
|
||||
}
|
||||
ARC2::inc('StoreTableManager');
|
||||
$mgr = new ARC2_StoreTableManager($this->a, $this);
|
||||
$mgr->createTables();
|
||||
}
|
||||
}
|
||||
|
||||
function extendColumns() {
|
||||
ARC2::inc('StoreTableManager');
|
||||
$mgr = new ARC2_StoreTableManager($this->a, $this);
|
||||
$mgr->extendColumns();
|
||||
$this->column_type = 'int';
|
||||
}
|
||||
|
||||
function splitTables() {
|
||||
ARC2::inc('StoreTableManager');
|
||||
$mgr = new ARC2_StoreTableManager($this->a, $this);
|
||||
$mgr->splitTables();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function hasSetting($k) {
|
||||
$tbl = $this->getTablePrefix() . 'setting';
|
||||
$sql = "SELECT val FROM " . $tbl . " WHERE k = '" .md5($k). "'";
|
||||
$rs = mysql_query($sql, $this->getDBCon());
|
||||
return ($rs && ($row = mysql_fetch_array($rs))) ? 1 : 0;
|
||||
}
|
||||
|
||||
function getSetting($k, $default = 0) {
|
||||
$tbl = $this->getTablePrefix() . 'setting';
|
||||
$sql = "SELECT val FROM " . $tbl . " WHERE k = '" .md5($k). "'";
|
||||
$rs = mysql_query($sql, $this->getDBCon());
|
||||
if ($rs && ($row = mysql_fetch_array($rs))) {
|
||||
return unserialize($row['val']);
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
function setSetting($k, $v) {
|
||||
$con = $this->getDBCon();
|
||||
$tbl = $this->getTablePrefix() . 'setting';
|
||||
if ($this->hasSetting($k)) {
|
||||
$sql = "UPDATE " .$tbl . " SET val = '" . mysql_real_escape_string(serialize($v), $con) . "' WHERE k = '" . md5($k) . "'";
|
||||
}
|
||||
else {
|
||||
$sql = "INSERT INTO " . $tbl . " (k, val) VALUES ('" . md5($k) . "', '" . mysql_real_escape_string(serialize($v), $con) . "')";
|
||||
}
|
||||
return mysql_query($sql, $con);
|
||||
}
|
||||
|
||||
function removeSetting($k) {
|
||||
$tbl = $this->getTablePrefix() . 'setting';
|
||||
return mysql_query("DELETE FROM " . $tbl . " WHERE k = '" . md5($k) . "'", $this->getDBCon());
|
||||
}
|
||||
|
||||
function getQueueTicket() {
|
||||
if (!$this->queue_queries) return 1;
|
||||
$t = 'ticket_' . substr(md5(uniqid(rand())), 0, 10);
|
||||
$con = $this->getDBCon();
|
||||
/* lock */
|
||||
$rs = mysql_query('LOCK TABLES ' . $this->getTablePrefix() . 'setting WRITE', $con);
|
||||
/* queue */
|
||||
$queue = $this->getSetting('query_queue', array());
|
||||
$queue[] = $t;
|
||||
$this->setSetting('query_queue', $queue);
|
||||
mysql_query('UNLOCK TABLES', $con);
|
||||
/* loop */
|
||||
$lc = 0;
|
||||
$queue = $this->getSetting('query_queue', array());
|
||||
while ($queue && ($queue[0] != $t) && ($lc < 30)) {
|
||||
if ($this->is_win) {
|
||||
sleep(1);
|
||||
$lc++;
|
||||
}
|
||||
else {
|
||||
usleep(100000);
|
||||
$lc += 0.1;
|
||||
}
|
||||
$queue = $this->getSetting('query_queue', array());
|
||||
}
|
||||
return ($lc < 30) ? $t : 0;
|
||||
}
|
||||
|
||||
function removeQueueTicket($t) {
|
||||
if (!$this->queue_queries) return 1;
|
||||
$con = $this->getDBCon();
|
||||
/* lock */
|
||||
mysql_query('LOCK TABLES ' . $this->getTablePrefix() . 'setting WRITE', $con);
|
||||
/* queue */
|
||||
$vals = $this->getSetting('query_queue', array());
|
||||
$pos = array_search($t, $vals);
|
||||
$queue = ($pos < (count($vals) - 1)) ? array_slice($vals, $pos + 1) : array();
|
||||
$this->setSetting('query_queue', $queue);
|
||||
mysql_query('UNLOCK TABLES', $con);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function reset($keep_settings = 0) {
|
||||
$con = $this->getDBCon();
|
||||
$tbls = $this->getTables();
|
||||
$prefix = $this->getTablePrefix();
|
||||
/* remove split tables */
|
||||
$ps = $this->getSetting('split_predicates', array());
|
||||
foreach ($ps as $p) {
|
||||
$tbl = 'triple_' . abs(crc32($p));
|
||||
mysql_query('DROP TABLE ' . $prefix . $tbl, $con);
|
||||
}
|
||||
$this->removeSetting('split_predicates');
|
||||
/* truncate tables */
|
||||
foreach ($tbls as $tbl) {
|
||||
if ($keep_settings && ($tbl == 'setting')) {
|
||||
continue;
|
||||
}
|
||||
mysql_query('TRUNCATE ' . $prefix . $tbl, $con);
|
||||
}
|
||||
}
|
||||
|
||||
function drop() {
|
||||
$con = $this->getDBCon();
|
||||
$tbls = $this->getTables();
|
||||
$prefix = $this->getTablePrefix();
|
||||
foreach ($tbls as $tbl) {
|
||||
mysql_query('DROP TABLE ' . $prefix . $tbl, $con);
|
||||
}
|
||||
}
|
||||
|
||||
function insert($doc, $g, $keep_bnode_ids = 0) {
|
||||
$doc = is_array($doc) ? $this->toTurtle($doc) : $doc;
|
||||
$infos = array('query' => array('url' => $g, 'target_graph' => $g));
|
||||
ARC2::inc('StoreLoadQueryHandler');
|
||||
$h =& new ARC2_StoreLoadQueryHandler($this->a, $this);
|
||||
$r = $h->runQuery($infos, $doc, $keep_bnode_ids);
|
||||
$this->processTriggers('insert', $infos);
|
||||
return $r;
|
||||
}
|
||||
|
||||
function delete($doc, $g) {
|
||||
if (!$doc) {
|
||||
$infos = array('query' => array('target_graphs' => array($g)));
|
||||
ARC2::inc('StoreDeleteQueryHandler');
|
||||
$h =& new ARC2_StoreDeleteQueryHandler($this->a, $this);
|
||||
$r = $h->runQuery($infos);
|
||||
$this->processTriggers('delete', $infos);
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
|
||||
function replace($doc, $g, $doc_2) {
|
||||
return array($this->delete($doc, $g), $this->insert($doc_2, $g));
|
||||
}
|
||||
|
||||
function dump() {
|
||||
ARC2::inc('StoreDumper');
|
||||
$d =& new ARC2_StoreDumper($this->a, $this);
|
||||
$d->dumpSPOG();
|
||||
}
|
||||
|
||||
function createBackup($path, $q = '') {
|
||||
ARC2::inc('StoreDumper');
|
||||
$d =& new ARC2_StoreDumper($this->a, $this);
|
||||
$d->saveSPOG($path, $q);
|
||||
}
|
||||
|
||||
function renameTo($name) {
|
||||
$con = $this->getDBCon();
|
||||
$tbls = $this->getTables();
|
||||
$old_prefix = $this->getTablePrefix();
|
||||
$new_prefix = $this->v('db_table_prefix', '', $this->a);
|
||||
$new_prefix .= $new_prefix ? '_' : '';
|
||||
$new_prefix .= $name . '_';
|
||||
foreach ($tbls as $tbl) {
|
||||
$rs = mysql_query('RENAME TABLE ' . $old_prefix . $tbl .' TO ' . $new_prefix . $tbl, $con);
|
||||
if ($er = mysql_error($con)) {
|
||||
return $this->addError($er);
|
||||
}
|
||||
}
|
||||
$this->a['store_name'] = $name;
|
||||
unset($this->tbl_prefix);
|
||||
}
|
||||
|
||||
function replicateTo($name) {
|
||||
$conf = array_merge($this->a, array('store_name' => $name));
|
||||
$new_store = ARC2::getStore($conf);
|
||||
$new_store->setUp();
|
||||
$new_store->reset();
|
||||
$con = $this->getDBCon();
|
||||
$tbls = $this->getTables();
|
||||
$old_prefix = $this->getTablePrefix();
|
||||
$new_prefix = $new_store->getTablePrefix();
|
||||
foreach ($tbls as $tbl) {
|
||||
$rs = mysql_query('INSERT IGNORE INTO ' . $new_prefix . $tbl .' SELECT * FROM ' . $old_prefix . $tbl, $con);
|
||||
if ($er = mysql_error($con)) {
|
||||
return $this->addError($er);
|
||||
}
|
||||
}
|
||||
return $new_store->query('SELECT COUNT(*) AS t_count WHERE { ?s ?p ?o}', 'row');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0) {
|
||||
if ($log_query) $this->logQuery($q);
|
||||
$con = $this->getDBCon();
|
||||
if (preg_match('/^dump/i', $q)) {
|
||||
$infos = array('query' => array('type' => 'dump'));
|
||||
}
|
||||
else {
|
||||
ARC2::inc('SPARQLPlusParser');
|
||||
$p = & new ARC2_SPARQLPlusParser($this->a, $this);
|
||||
$p->parse($q, $src);
|
||||
$infos = $p->getQueryInfos();
|
||||
}
|
||||
if ($result_format == 'infos') return $infos;
|
||||
$infos['result_format'] = $result_format;
|
||||
if (!isset($p) || !$p->getErrors()) {
|
||||
$qt = $infos['query']['type'];
|
||||
if (!in_array($qt, array('select', 'ask', 'describe', 'construct', 'load', 'insert', 'delete', 'dump'))) {
|
||||
return $this->addError('Unsupported query type "'.$qt.'"');
|
||||
}
|
||||
$t1 = ARC2::mtime();
|
||||
$r = array('query_type' => $qt, 'result' => $this->runQuery($infos, $qt, $keep_bnode_ids, $q));
|
||||
$t2 = ARC2::mtime();
|
||||
$r['query_time'] = $t2 - $t1;
|
||||
/* query result */
|
||||
if ($result_format == 'raw') {
|
||||
return $r['result'];
|
||||
}
|
||||
if ($result_format == 'rows') {
|
||||
return $r['result']['rows'] ? $r['result']['rows'] : array();
|
||||
}
|
||||
if ($result_format == 'row') {
|
||||
return $r['result']['rows'] ? $r['result']['rows'][0] : array();
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function runQuery($infos, $type, $keep_bnode_ids = 0, $q = '') {
|
||||
ARC2::inc('Store' . ucfirst($type) . 'QueryHandler');
|
||||
$cls = 'ARC2_Store' . ucfirst($type) . 'QueryHandler';
|
||||
$h =& new $cls($this->a, $this);
|
||||
$ticket = 1;
|
||||
$r = array();
|
||||
if ($q && ($type == 'select')) $ticket = $this->getQueueTicket($q);
|
||||
if ($ticket) {
|
||||
if ($type == 'load') {/* the LoadQH supports raw data as 2nd parameter */
|
||||
$r = $h->runQuery($infos, '', $keep_bnode_ids);
|
||||
}
|
||||
else {
|
||||
$r = $h->runQuery($infos, $keep_bnode_ids);
|
||||
}
|
||||
}
|
||||
if ($q && ($type == 'select')) $this->removeQueueTicket($ticket);
|
||||
$trigger_r = $this->processTriggers($type, $infos);
|
||||
return $r;
|
||||
}
|
||||
|
||||
function processTriggers($type, $infos) {
|
||||
$r = array();
|
||||
$trigger_defs = $this->triggers;
|
||||
$this->triggers = array();
|
||||
if ($triggers = $this->v($type, array(), $trigger_defs)) {
|
||||
$r['trigger_results'] = array();
|
||||
$triggers = is_array($triggers) ? $triggers : array($triggers);
|
||||
$trigger_inc_path = $this->v('store_triggers_path', '', $this->a);
|
||||
foreach ($triggers as $trigger) {
|
||||
$trigger .= !preg_match('/Trigger$/', $trigger) ? 'Trigger' : '';
|
||||
if (ARC2::inc(ucfirst($trigger), $trigger_inc_path)) {
|
||||
$cls = 'ARC2_' . ucfirst($trigger);
|
||||
$config = array_merge($this->a, array('query_infos' => $infos));
|
||||
$trigger_obj = new $cls($config, $this);
|
||||
if (method_exists($trigger_obj, 'go')) {
|
||||
$r['trigger_results'][] = $trigger_obj->go();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->triggers = $trigger_defs;
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTermID($val, $term = '') {
|
||||
$tbl = preg_match('/^(s|o)$/', $term) ? $term . '2val' : 'id2val';
|
||||
$con = $this->getDBCon();
|
||||
$sql = "SELECT id FROM " . $this->getTablePrefix() . $tbl . " WHERE val = BINARY '" . mysql_real_escape_string($val, $con) . "' LIMIT 1";
|
||||
if (($rs = mysql_query($sql, $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
|
||||
return $row['id'];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getLock($t_out = 10, $t_out_init = '') {
|
||||
if (!$t_out_init) $t_out_init = $t_out;
|
||||
$con = $this->getDBCon();
|
||||
$l_name = $this->a['db_name'] . '.' . $this->getTablePrefix() . '.write_lock';
|
||||
if ($rs = mysql_query('SELECT IS_FREE_LOCK("' . $l_name. '") AS success', $con)) {
|
||||
$row = mysql_fetch_array($rs);
|
||||
if (!$row['success']) {
|
||||
if ($t_out) {
|
||||
sleep(1);
|
||||
return $this->getLock($t_out - 1, $t_out_init);
|
||||
}
|
||||
}
|
||||
elseif ($rs = mysql_query('SELECT GET_LOCK("' . $l_name. '", ' . $t_out_init. ') AS success', $con)) {
|
||||
$row = mysql_fetch_array($rs);
|
||||
return $row['success'];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function releaseLock() {
|
||||
$con = $this->getDBCon();
|
||||
return mysql_query('DO RELEASE_LOCK("' . $this->a['db_name'] . '.' . $this->getTablePrefix() . '.write_lock")', $con);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function processTables($level = 2, $operation = 'optimize') {/* 1: triple + g2t, 2: triple + *2val, 3: all tables */
|
||||
$con = $this->getDBCon();
|
||||
$pre = $this->getTablePrefix();
|
||||
$tbls = $this->getTables();
|
||||
$sql = '';
|
||||
foreach ($tbls as $tbl) {
|
||||
if (($level < 3) && preg_match('/(backup|setting)$/', $tbl)) continue;
|
||||
if (($level < 2) && preg_match('/(val)$/', $tbl)) continue;
|
||||
$sql .= $sql ? ', ' : strtoupper($operation) . ' TABLE ';
|
||||
$sql .= $pre . $tbl;
|
||||
}
|
||||
mysql_query($sql, $con);
|
||||
if ($err = mysql_error($con)) $this->addError($err . ' in ' . $sql);
|
||||
}
|
||||
|
||||
function optimizeTables($level = 2) {
|
||||
return $this->processTables($level, 'optimize');
|
||||
}
|
||||
|
||||
function checkTables($level = 2) {
|
||||
return $this->processTables($level, 'check');
|
||||
}
|
||||
|
||||
function repairTables($level = 2) {
|
||||
return $this->processTables($level, 'repair');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function changeNamespaceURI($old_uri, $new_uri) {
|
||||
ARC2::inc('StoreHelper');
|
||||
$c = new ARC2_StoreHelper($this->a, $this);
|
||||
return $c->changeNamespaceURI($old_uri, $new_uri);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getResourceLabel($res, $unnamed_label = 'An unnamed resource') {
|
||||
if (!isset($this->resource_labels)) $this->resource_labels = array();
|
||||
if (isset($this->resource_labels[$res])) return $this->resource_labels[$res];
|
||||
if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) return $res;/* literal */
|
||||
$ps = $this->getLabelProps();
|
||||
if ($this->getSetting('store_label_properties', '-') != md5(serialize($ps))) {
|
||||
$this->inferLabelProps($ps);
|
||||
}
|
||||
//$sub_q .= $sub_q ? ' || ' : '';
|
||||
//$sub_q .= 'REGEX(str(?p), "(last_name|name|fn|title|label)$", "i")';
|
||||
$q = 'SELECT ?label WHERE { <' . $res . '> ?p ?label . ?p a <http://semsol.org/ns/arc#LabelProperty> } LIMIT 3';
|
||||
$r = '';
|
||||
if ($rows = $this->query($q, 'rows')) {
|
||||
foreach ($rows as $row) {
|
||||
$r = strlen($row['label']) > strlen($r) ? $row['label'] : $r;
|
||||
}
|
||||
}
|
||||
if (!$r && preg_match('/^\_\:/', $res)) {
|
||||
return $unnamed_label;
|
||||
}
|
||||
$r = $r ? $r : preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
|
||||
$r = str_replace('_', ' ', $r);
|
||||
$r = preg_replace('/([a-z])([A-Z])/e', '"\\1 " . strtolower("\\2")', $r);
|
||||
$this->resource_labels[$res] = $r;
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getLabelProps() {
|
||||
return array_merge(
|
||||
$this->v('rdf_label_properties' , array(), $this->a),
|
||||
array(
|
||||
'http://www.w3.org/2000/01/rdf-schema#label',
|
||||
'http://xmlns.com/foaf/0.1/name',
|
||||
'http://purl.org/dc/elements/1.1/title',
|
||||
'http://purl.org/rss/1.0/title',
|
||||
'http://www.w3.org/2004/02/skos/core#prefLabel',
|
||||
'http://xmlns.com/foaf/0.1/nick',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function inferLabelProps($ps) {
|
||||
$this->query('DELETE FROM <label-properties>');
|
||||
$sub_q = '';
|
||||
foreach ($ps as $p) {
|
||||
$sub_q .= ' <' . $p . '> a <http://semsol.org/ns/arc#LabelProperty> . ';
|
||||
}
|
||||
$this->query('INSERT INTO <label-properties> { ' . $sub_q. ' }');
|
||||
$this->setSetting('store_label_properties', md5(serialize($ps)));
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getResourcePredicates($res) {
|
||||
$r = array();
|
||||
if ($rows = $this->query('SELECT DISTINCT ?p WHERE { <' . $res . '> ?p ?o . }', 'rows')) {
|
||||
foreach ($rows as $row) {
|
||||
$r[$row['p']] = array();
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getDomains($p) {
|
||||
$r = array();
|
||||
foreach($this->query('SELECT DISTINCT ?type WHERE {?s <' . $p . '> ?o ; a ?type . }', 'rows') as $row) {
|
||||
$r[] = $row['type'];
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getPredicateRange($p) {
|
||||
$row = $this->query('SELECT ?val WHERE {<' . $p . '> rdfs:range ?val . } LIMIT 1', 'row');
|
||||
return $row ? $row['val'] : '';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function logQuery($q) {
|
||||
$fp = @fopen("arc_query_log.txt", "a");
|
||||
@fwrite($fp, date('Y-m-d\TH:i:s\Z', time()) . ' : ' . $q . '' . "\n\n");
|
||||
@fclose($fp);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
57
arc/store/ARC2_StoreAskQueryHandler.php
Normal file
57
arc/store/ARC2_StoreAskQueryHandler.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 SPARQL ASK query handler
|
||||
*
|
||||
* @author Benjamin Nowack
|
||||
* @license <http://arc.semsol.org/license>
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-12-15
|
||||
*/
|
||||
|
||||
ARC2::inc('StoreSelectQueryHandler');
|
||||
|
||||
class ARC2_StoreAskQueryHandler extends ARC2_StoreSelectQueryHandler {
|
||||
|
||||
function __construct($a = '', &$caller) {/* caller has to be a store */
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreAskQueryHandler($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* db_con */
|
||||
parent::__init();
|
||||
$this->store =& $this->caller;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function runQuery($infos) {
|
||||
$infos['query']['limit'] = 1;
|
||||
$this->infos = $infos;
|
||||
$this->buildResultVars();
|
||||
return parent::runQuery($this->infos);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function buildResultVars() {
|
||||
$this->infos['query']['result_vars'][] = array('var' => '1', 'aggregate' => '', 'alias' => 'success');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getFinalQueryResult($q_sql, $tmp_tbl) {
|
||||
$con = $this->store->getDBCon();
|
||||
$rs = mysql_query('SELECT success FROM ' . $tmp_tbl, $con);
|
||||
$r = ($row = mysql_fetch_array($rs)) ? $row['success'] : 0;
|
||||
return $r ? true : false;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
|
||||
|
||||
36
arc/store/ARC2_StoreAtomLoader.php
Normal file
36
arc/store/ARC2_StoreAtomLoader.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Store Atom(2) Loader
|
||||
author: Benjamin Nowack
|
||||
version: 2008-09-26
|
||||
*/
|
||||
|
||||
ARC2::inc('AtomParser');
|
||||
|
||||
class ARC2_StoreAtomLoader extends ARC2_AtomParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreAtomLoader($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function addT($t) {
|
||||
$this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
|
||||
$this->t_count++;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
40
arc/store/ARC2_StoreCBJSONLoader.php
Normal file
40
arc/store/ARC2_StoreCBJSONLoader.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Store CrunchBase API JSON Loader
|
||||
author: Benjamin Nowack
|
||||
version: 2008-07-15
|
||||
*/
|
||||
|
||||
ARC2::inc('CBJSONParser');
|
||||
|
||||
class ARC2_StoreCBJSONLoader extends ARC2_CBJSONParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreCBJSONLoader($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function done() {
|
||||
$this->extractRDF();
|
||||
}
|
||||
|
||||
function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
|
||||
$this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
|
||||
$this->t_count++;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
119
arc/store/ARC2_StoreConstructQueryHandler.php
Normal file
119
arc/store/ARC2_StoreConstructQueryHandler.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 RDF Store CONSTRUCT Query Handler
|
||||
author: Benjamin Nowack
|
||||
version: 2008-02-11 (Fix: auto-adding DISTINCT to avoid unnecessary duplicates)
|
||||
*/
|
||||
|
||||
ARC2::inc('StoreSelectQueryHandler');
|
||||
|
||||
class ARC2_StoreConstructQueryHandler extends ARC2_StoreSelectQueryHandler {
|
||||
|
||||
function __construct($a = '', &$caller) {/* caller has to be a store */
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreConstructQueryHandler($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* db_con */
|
||||
parent::__init();
|
||||
$this->store =& $this->caller;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function runQuery($infos) {
|
||||
$this->infos = $infos;
|
||||
$this->buildResultVars();
|
||||
$this->infos['query']['distinct'] = 1;
|
||||
$sub_r = parent::runQuery($this->infos);
|
||||
$rf = $this->v('result_format', '', $infos);
|
||||
if (in_array($rf, array('sql', 'structure', 'index'))) {
|
||||
return $sub_r;
|
||||
}
|
||||
return $this->getResultIndex($sub_r);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function buildResultVars() {
|
||||
$r = array();
|
||||
foreach ($this->infos['query']['construct_triples'] as $t) {
|
||||
foreach (array('s', 'p', 'o') as $term) {
|
||||
if ($t[$term . '_type'] == 'var') {
|
||||
if (!in_array($t[$term], $r)) {
|
||||
$r[] = array('var' => $t[$term], 'aggregate' => '', 'alias' => '');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->infos['query']['result_vars'] = $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getResultIndex($qr) {
|
||||
$r = array();
|
||||
$added = array();
|
||||
$rows = $this->v('rows', array(), $qr);
|
||||
$cts = $this->infos['query']['construct_triples'];
|
||||
$bnc = 0;
|
||||
foreach ($rows as $row) {
|
||||
$bnc++;
|
||||
foreach ($cts as $ct) {
|
||||
$skip_t = 0;
|
||||
$t = array();
|
||||
foreach (array('s', 'p', 'o') as $term) {
|
||||
$val = $ct[$term];
|
||||
$type = $ct[$term . '_type'];
|
||||
$val = ($type == 'bnode') ? $val . $bnc : $val;
|
||||
if ($type == 'var') {
|
||||
$skip_t = !isset($row[$val]) ? 1 : $skip_t;
|
||||
$type = !$skip_t ? $row[$val . ' type'] : '';
|
||||
$val = (!$skip_t) ? $row[$val] : '';
|
||||
}
|
||||
$t[$term] = $val;
|
||||
$t[$term . '_type'] = $type;
|
||||
if (isset($row[$term . ' lang'])) {
|
||||
$t[$term . '_lang'] = $row[$term . ' lang'];
|
||||
}
|
||||
if (isset($row[$term . ' datatype'])) {
|
||||
$t[$term . '_datatype'] = $row[$term . ' datatype'];
|
||||
}
|
||||
}
|
||||
if (!$skip_t) {
|
||||
$s = $t['s'];
|
||||
$p = $t['p'];
|
||||
$o = $t['o'];
|
||||
if (!isset($r[$s])) {
|
||||
$r[$s] = array();
|
||||
}
|
||||
if (!isset($r[$s][$p])) {
|
||||
$r[$s][$p] = array();
|
||||
}
|
||||
$o = array('value' => $o);
|
||||
foreach (array('lang', 'type', 'datatype') as $suffix) {
|
||||
if (isset($t['o_' . $suffix]) && $t['o_' . $suffix]) {
|
||||
$o[$suffix] = $t['o_' . $suffix];
|
||||
}
|
||||
}
|
||||
if (!isset($added[md5($s . ' ' . $p . ' ' . serialize($o))])) {
|
||||
$r[$s][$p][] = $o;
|
||||
$added[md5($s . ' ' . $p . ' ' . serialize($o))] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
|
||||
|
||||
229
arc/store/ARC2_StoreDeleteQueryHandler.php
Normal file
229
arc/store/ARC2_StoreDeleteQueryHandler.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 RDF Store DELETE Query Handler
|
||||
author: Benjamin Nowack
|
||||
version: 2009-06-15 (Addition: cleanValueTables method)
|
||||
*/
|
||||
|
||||
ARC2::inc('StoreQueryHandler');
|
||||
|
||||
class ARC2_StoreDeleteQueryHandler extends ARC2_StoreQueryHandler {
|
||||
|
||||
function __construct($a = '', &$caller) {/* caller has to be a store */
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreDeleteQueryHandler($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* db_con */
|
||||
parent::__init();
|
||||
$this->store =& $this->caller;
|
||||
$this->handler_type = 'delete';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function runQuery($infos) {
|
||||
$this->infos = $infos;
|
||||
$con = $this->store->getDBCon();
|
||||
$t1 = ARC2::mtime();
|
||||
/* delete */
|
||||
$this->refs_deleted = false;
|
||||
/* graph(s) only */
|
||||
if (!$this->v('construct_triples', array(), $this->infos['query'])) {
|
||||
$tc = $this->deleteTargetGraphs();
|
||||
}
|
||||
/* graph(s) + explicit triples */
|
||||
elseif (!$this->v('pattern', array(), $this->infos['query'])) {
|
||||
$tc = $this->deleteTriples();
|
||||
}
|
||||
/* graph(s) + constructed triples */
|
||||
else {
|
||||
$tc = $this->deleteConstructedGraph();
|
||||
}
|
||||
$t2 = ARC2::mtime();
|
||||
/* clean up */
|
||||
if ($tc && ($this->refs_deleted || (rand(1, 100) == 1))) $this->cleanTableReferences();
|
||||
if ($tc && (rand(1, 50) == 1)) $this->store->optimizeTables();
|
||||
if ($tc && (rand(1, 500) == 1)) $this->cleanValueTables();
|
||||
$t3 = ARC2::mtime();
|
||||
$index_dur = round($t3 - $t2, 4);
|
||||
$dur = round($t3 - $t1, 4);
|
||||
return array(
|
||||
't_count' => $tc,
|
||||
'delete_time' => $dur,
|
||||
'index_update_time' => $index_dur,
|
||||
);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function deleteTargetGraphs() {
|
||||
$tbl_prefix = $this->store->getTablePrefix();
|
||||
$r = 0;
|
||||
$con = $this->store->getDBCon();
|
||||
foreach ($this->infos['query']['target_graphs'] as $g) {
|
||||
if ($g_id = $this->getTermID($g, 'g')) {
|
||||
$rs = mysql_query('DELETE FROM ' . $tbl_prefix . 'g2t WHERE g = ' .$g_id, $con);
|
||||
$r += mysql_affected_rows($con);
|
||||
}
|
||||
}
|
||||
$this->refs_deleted = $r ? 1 : 0;
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function deleteTriples() {
|
||||
$r = 0;
|
||||
$dbv = $this->store->getDBVersion();
|
||||
$tbl_prefix = $this->store->getTablePrefix();
|
||||
$con = $this->store->getDBCon();
|
||||
/* graph restriction */
|
||||
$tgs = $this->infos['query']['target_graphs'];
|
||||
$gq = '';
|
||||
foreach ($tgs as $g) {
|
||||
if ($g_id = $this->getTermID($g, 'g')) {
|
||||
$gq .= $gq ? ', ' . $g_id : $g_id;
|
||||
}
|
||||
}
|
||||
$gq = $gq ? ' AND G.g IN (' . $gq . ')' : '';
|
||||
/* triples */
|
||||
foreach ($this->infos['query']['construct_triples'] as $t) {
|
||||
$q = '';
|
||||
$skip = 0;
|
||||
foreach (array('s', 'p', 'o') as $term) {
|
||||
if (isset($t[$term . '_type']) && preg_match('/(var)/', $t[$term . '_type'])) {
|
||||
//$skip = 1;
|
||||
}
|
||||
else {
|
||||
$term_id = $this->getTermID($t[$term], $term);
|
||||
$q .= $q ? ' AND ' : '';
|
||||
$q .= 'T.' . $term . '=' . $term_id;
|
||||
}
|
||||
}
|
||||
if ($skip) {
|
||||
continue;
|
||||
}
|
||||
if ($gq) {
|
||||
$sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'g2t' : 'DELETE G';
|
||||
$sql .= '
|
||||
FROM ' . $tbl_prefix . 'g2t G
|
||||
JOIN ' . $this->getTripleTable() . ' T ON (T.t = G.t' . $gq . ')
|
||||
WHERE ' . $q . '
|
||||
';
|
||||
$this->refs_deleted = 1;
|
||||
}
|
||||
else {/* triples only */
|
||||
$sql = ($dbv < '04-01') ? 'DELETE ' . $this->getTripleTable() : 'DELETE T';
|
||||
$sql .= ' FROM ' . $this->getTripleTable() . ' T WHERE ' . $q;
|
||||
}
|
||||
$rs = mysql_query($sql, $con);
|
||||
if ($er = mysql_error($con)) {
|
||||
$this->addError($er .' in ' . $sql);
|
||||
}
|
||||
$r += mysql_affected_rows($con);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function deleteConstructedGraph() {
|
||||
ARC2::inc('StoreConstructQueryHandler');
|
||||
$h =& new ARC2_StoreConstructQueryHandler($this->a, $this->store);
|
||||
$sub_r = $h->runQuery($this->infos);
|
||||
$triples = ARC2::getTriplesFromIndex($sub_r);
|
||||
$tgs = $this->infos['query']['target_graphs'];
|
||||
$this->infos = array('query' => array('construct_triples' => $triples, 'target_graphs' => $tgs));
|
||||
return $this->deleteTriples();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function cleanTableReferences() {
|
||||
/* lock */
|
||||
if (!$this->store->getLock()) return $this->addError('Could not get lock in "cleanTableReferences"');
|
||||
$con = $this->store->getDBCon();
|
||||
$tbl_prefix = $this->store->getTablePrefix();
|
||||
$dbv = $this->store->getDBVersion();
|
||||
/* check for unconnected triples */
|
||||
$sql = '
|
||||
SELECT T.t FROM '. $tbl_prefix . 'triple T LEFT JOIN '. $tbl_prefix . 'g2t G ON ( G.t = T.t )
|
||||
WHERE G.t IS NULL LIMIT 1
|
||||
';
|
||||
if (($rs = mysql_query($sql, $con)) && mysql_num_rows($rs)) {
|
||||
/* delete unconnected triples */
|
||||
$sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'triple' : 'DELETE T';
|
||||
$sql .= '
|
||||
FROM ' . $tbl_prefix . 'triple T
|
||||
LEFT JOIN ' . $tbl_prefix . 'g2t G ON (G.t = T.t)
|
||||
WHERE G.t IS NULL
|
||||
';
|
||||
mysql_query($sql, $con);
|
||||
}
|
||||
/* check for unconnected graph refs */
|
||||
if ((rand(1, 100) == 1)) {
|
||||
$sql = '
|
||||
SELECT G.g FROM '. $tbl_prefix . 'g2t G LEFT JOIN '. $tbl_prefix . 'triple T ON ( T.t = G.t )
|
||||
WHERE T.t IS NULL LIMIT 1
|
||||
';
|
||||
if (($rs = mysql_query($sql, $con)) && mysql_num_rows($rs)) {
|
||||
/* delete unconnected graph refs */
|
||||
$sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'g2t' : 'DELETE G';
|
||||
$sql .= '
|
||||
FROM ' . $tbl_prefix . 'g2t G
|
||||
LEFT JOIN ' . $tbl_prefix . 'triple T ON (T.t = G.t)
|
||||
WHERE T.t IS NULL
|
||||
';
|
||||
mysql_query($sql, $con);
|
||||
}
|
||||
}
|
||||
/* release lock */
|
||||
$this->store->releaseLock();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function cleanValueTables() {
|
||||
/* lock */
|
||||
if (!$this->store->getLock()) return $this->addError('Could not get lock in "cleanValueTables"');
|
||||
$con = $this->store->getDBCon();
|
||||
$tbl_prefix = $this->store->getTablePrefix();
|
||||
$dbv = $this->store->getDBVersion();
|
||||
/* o2val */
|
||||
$sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'o2val' : 'DELETE V';
|
||||
$sql .= '
|
||||
FROM ' . $tbl_prefix . 'o2val V
|
||||
LEFT JOIN ' . $tbl_prefix . 'triple T ON (T.o = V.id)
|
||||
WHERE T.t IS NULL
|
||||
';
|
||||
mysql_query($sql, $con);
|
||||
/* s2val */
|
||||
$sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 's2val' : 'DELETE V';
|
||||
$sql .= '
|
||||
FROM ' . $tbl_prefix . 's2val V
|
||||
LEFT JOIN ' . $tbl_prefix . 'triple T ON (T.s = V.id)
|
||||
WHERE T.t IS NULL
|
||||
';
|
||||
mysql_query($sql, $con);
|
||||
/* id2val */
|
||||
$sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'id2val' : 'DELETE V';
|
||||
$sql .= '
|
||||
FROM ' . $tbl_prefix . 'id2val V
|
||||
LEFT JOIN ' . $tbl_prefix . 'g2t G ON (G.g = V.id)
|
||||
LEFT JOIN ' . $tbl_prefix . 'triple T1 ON (T1.p = V.id)
|
||||
LEFT JOIN ' . $tbl_prefix . 'triple T2 ON (T2.o_lang_dt = V.id)
|
||||
WHERE G.g IS NULL AND T1.t IS NULL AND T2.t IS NULL
|
||||
';
|
||||
//mysql_query($sql, $con);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
123
arc/store/ARC2_StoreDescribeQueryHandler.php
Normal file
123
arc/store/ARC2_StoreDescribeQueryHandler.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Store DESCRIBE Query Handler
|
||||
author: Benjamin Nowack
|
||||
version: 2008-01-09 (Tweak: label auto-detection is now optional)
|
||||
*/
|
||||
|
||||
ARC2::inc('StoreSelectQueryHandler');
|
||||
|
||||
class ARC2_StoreDescribeQueryHandler extends ARC2_StoreSelectQueryHandler {
|
||||
|
||||
function __construct($a = '', &$caller) {/* caller has to be a store */
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreDescribeQueryHandler($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* db_con */
|
||||
parent::__init();
|
||||
$this->store =& $this->caller;
|
||||
$this->detect_labels = $this->v('detect_describe_query_labels', 0, $this->a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function runQuery($infos) {
|
||||
$ids = $infos['query']['result_uris'];
|
||||
if ($vars = $infos['query']['result_vars']) {
|
||||
$sub_r = parent::runQuery($infos);
|
||||
$rf = $this->v('result_format', '', $infos);
|
||||
if (in_array($rf, array('sql', 'structure', 'index'))) {
|
||||
return $sub_r;
|
||||
}
|
||||
$rows = $this->v('rows', array(), $sub_r);
|
||||
foreach ($rows as $row) {
|
||||
foreach ($vars as $info) {
|
||||
$val = isset($row[$info['var']]) ? $row[$info['var']] : '';
|
||||
if ($val && ($row[$info['var'] . ' type'] != 'literal') && !in_array($val, $ids)) {
|
||||
$ids[] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->r = array();
|
||||
$this->described_ids = array();
|
||||
$this->ids = $ids;
|
||||
$this->added_triples = array();
|
||||
$is_sub_describe = 0;
|
||||
while ($this->ids) {
|
||||
$id = $this->ids[0];
|
||||
$this->described_ids[] = $id;
|
||||
if ($this->detect_labels) {
|
||||
$q = '
|
||||
CONSTRUCT {
|
||||
<' . $id . '> ?p ?o .
|
||||
?o ?label_p ?o_label .
|
||||
?o <http://arc.semsol.org/ns/arc#label> ?o_label .
|
||||
} WHERE {
|
||||
<' . $id . '> ?p ?o .
|
||||
OPTIONAL {
|
||||
?o ?label_p ?o_label .
|
||||
FILTER REGEX(str(?label_p), "(name|label|title|summary|nick|fn)$", "i")
|
||||
}
|
||||
}
|
||||
';
|
||||
}
|
||||
else {
|
||||
$q = '
|
||||
CONSTRUCT {
|
||||
<' . $id . '> ?p ?o .
|
||||
} WHERE {
|
||||
<' . $id . '> ?p ?o .
|
||||
}
|
||||
';
|
||||
}
|
||||
$sub_r = $this->store->query($q);
|
||||
$sub_index = is_array($sub_r['result']) ? $sub_r['result'] : array();
|
||||
$this->mergeSubResults($sub_index, $is_sub_describe);
|
||||
$is_sub_describe = 1;
|
||||
}
|
||||
return $this->r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function mergeSubResults($index, $is_sub_describe = 1) {
|
||||
foreach ($index as $s => $ps) {
|
||||
if (!isset($this->r[$s])) $this->r[$s] = array();
|
||||
foreach ($ps as $p => $os) {
|
||||
if (!isset($this->r[$s][$p])) $this->r[$s][$p] = array();
|
||||
foreach ($os as $o) {
|
||||
$id = md5($s . ' ' . $p . ' ' . serialize($o));
|
||||
if (!isset($this->added_triples[$id])) {
|
||||
if (1 || !$is_sub_describe) {
|
||||
$this->r[$s][$p][] = $o;
|
||||
if (is_array($o) && ($o['type'] == 'bnode') && !in_array($o['value'], $this->ids)) $this->ids[] = $o['value'];
|
||||
}
|
||||
elseif (!is_array($o) || ($o['type'] != 'bnode')) {
|
||||
$this->r[$s][$p][] = $o;
|
||||
}
|
||||
$this->added_triples[$id] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* adjust ids */
|
||||
$ids = $this->ids;
|
||||
$this->ids = array();
|
||||
foreach ($ids as $id) {
|
||||
if (!in_array($id, $this->described_ids)) $this->ids[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
|
||||
|
||||
41
arc/store/ARC2_StoreDumpQueryHandler.php
Normal file
41
arc/store/ARC2_StoreDumpQueryHandler.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 RDF Store DUMP Query Handler
|
||||
author: Benjamin Nowack
|
||||
version: 2008-07-02
|
||||
*/
|
||||
|
||||
ARC2::inc('StoreQueryHandler');
|
||||
|
||||
class ARC2_StoreDumpQueryHandler extends ARC2_StoreQueryHandler {
|
||||
|
||||
function __construct($a = '', &$caller) {/* caller has to be a store */
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreDumpQueryHandler($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* db_con */
|
||||
parent::__init();
|
||||
$this->store =& $this->caller;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function runQuery($infos, $keep_bnode_ids = 0) {
|
||||
$this->infos = $infos;
|
||||
$con = $this->store->getDBCon();
|
||||
ARC2::inc('StoreDumper');
|
||||
$d =& new ARC2_StoreDumper($this->a, $this->store);
|
||||
$d->dumpSPOG();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
157
arc/store/ARC2_StoreDumper.php
Normal file
157
arc/store/ARC2_StoreDumper.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Store Dumper
|
||||
author: Benjamin Nowack
|
||||
version: 2008-07-02
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_StoreDumper extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreDumper($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
$this->store =& $this->caller;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function dumpSPOG() {
|
||||
$con = $this->store->getDBCon();
|
||||
$rs = $this->getRecordset();
|
||||
if ($er = mysql_error($con)) $this->addError($er);
|
||||
header('Content-Type: application/sparql-results+xml');
|
||||
//header('Content-Type: text/plain');
|
||||
echo $this->getHeader();
|
||||
if ($rs) {
|
||||
while ($row = mysql_fetch_array($rs)) {
|
||||
echo $this->getEntry($row);
|
||||
}
|
||||
}
|
||||
echo $this->getFooter();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function saveSPOG($path, $q = '') {
|
||||
$con = $this->store->getDBCon();
|
||||
$rs = $q ? $this->store->query($q, 'rows') : $this->getRecordset();
|
||||
if ($er = mysql_error($con)) return $this->addError($er);
|
||||
if (!$fp = @fopen($path, 'w')) return $this->addError('Could not create backup file at ' . realpath($path));
|
||||
fwrite($fp, $this->getHeader());
|
||||
if ($rs) {
|
||||
if ($q) {
|
||||
foreach ($rs as $row) {
|
||||
fwrite($fp, $this->getEntry($row));
|
||||
}
|
||||
}
|
||||
else {
|
||||
while ($row = mysql_fetch_array($rs)) {
|
||||
fwrite($fp, $this->getEntry($row));
|
||||
}
|
||||
}
|
||||
}
|
||||
fwrite($fp, $this->getFooter());
|
||||
@fclose($fp);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getRecordset() {
|
||||
$prefix = $this->store->getTablePrefix();
|
||||
$con = $this->store->getDBCon();
|
||||
$sql = '
|
||||
SELECT
|
||||
VS.val AS s,
|
||||
T.s_type AS `s type`,
|
||||
VP.val AS p,
|
||||
0 AS `p type`,
|
||||
VO.val AS o,
|
||||
T.o_type AS `o type`,
|
||||
VLDT.val as `o lang_dt`,
|
||||
VG.val as g,
|
||||
0 AS `g type`
|
||||
FROM
|
||||
' . $prefix . 'triple T
|
||||
JOIN ' . $prefix . 's2val VS ON (T.s = VS.id)
|
||||
JOIN ' . $prefix . 'id2val VP ON (T.p = VP.id)
|
||||
JOIN ' . $prefix . 'o2val VO ON (T.o = VO.id)
|
||||
JOIN ' . $prefix . 'id2val VLDT ON (T.o_lang_dt = VLDT.id)
|
||||
JOIN ' . $prefix . 'g2t G2T ON (T.t = G2T.t)
|
||||
JOIN ' . $prefix . 'id2val VG ON (G2T.g = VG.id)
|
||||
';
|
||||
return mysql_unbuffered_query($sql, $con);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getHeader() {
|
||||
$n = "\n";
|
||||
return '' .
|
||||
'<?xml version="1.0"?>' .
|
||||
$n . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
|
||||
$n . ' <head>' .
|
||||
$n . ' <variable name="s"/>' .
|
||||
$n . ' <variable name="p"/>' .
|
||||
$n . ' <variable name="o"/>' .
|
||||
$n . ' <variable name="g"/>' .
|
||||
$n . ' </head>' .
|
||||
$n . ' <results>' .
|
||||
'';
|
||||
}
|
||||
|
||||
function getEntry($row) {
|
||||
$n = "\n";
|
||||
$r = '';
|
||||
$r .= $n . ' <result>';
|
||||
foreach (array('s', 'p', 'o', 'g') as $var) {
|
||||
if (isset($row[$var])) {
|
||||
$type = (string) $row[$var . ' type'];
|
||||
$r .= $n . ' <binding name="' . $var . '">';
|
||||
if (($type == '0') || ($type == 'uri')) {
|
||||
$r .= $n . ' <uri>' . htmlspecialchars($row[$var]) . '</uri>';
|
||||
}
|
||||
elseif (($type == '1') || ($type == 'bnode')) {
|
||||
$r .= $n . ' <bnode>' . substr($row[$var], 2) . '</bnode>';
|
||||
}
|
||||
else {
|
||||
$lang_dt = '';
|
||||
foreach (array('o lang_dt', 'o lang', 'o datatype') as $k) {
|
||||
if (($var == 'o') && isset($row[$k]) && $row[$k]) $lang_dt = $row[$k];
|
||||
}
|
||||
$is_lang = preg_match('/^([a-z]+(\-[a-z0-9]+)*)$/i', $lang_dt);
|
||||
list($lang, $dt) = $is_lang ? array($lang_dt, '') : array('', $lang_dt);
|
||||
$lang = $lang ? ' xml:lang="' . $lang . '"' : '';
|
||||
$dt = $dt ? ' datatype="' . htmlspecialchars($dt) . '"' : '';
|
||||
$r .= $n . ' <literal' . $dt . $lang . '>' . htmlspecialchars($row[$var]) . '</literal>';
|
||||
}
|
||||
$r .= $n . ' </binding>';
|
||||
}
|
||||
}
|
||||
$r .= $n . ' </result>';
|
||||
return $r;
|
||||
}
|
||||
|
||||
function getFooter() {
|
||||
$n = "\n";
|
||||
return '' .
|
||||
$n . ' </results>' .
|
||||
$n . '</sparql>' .
|
||||
$n .
|
||||
'';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
1077
arc/store/ARC2_StoreEndpoint.php
Normal file
1077
arc/store/ARC2_StoreEndpoint.php
Normal file
File diff suppressed because it is too large
Load Diff
70
arc/store/ARC2_StoreHelper.php
Normal file
70
arc/store/ARC2_StoreHelper.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 RDF Store Helper
|
||||
author: Benjamin Nowack
|
||||
version: 2008-04-03 (Tweak: Changed locking approach from "LOCK TABLE" to "GET LOCK")
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_StoreHelper extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreHelper($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* db_con */
|
||||
parent::__init();
|
||||
$this->store =& $this->caller;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function changeNamespaceURI($old_uri, $new_uri) {
|
||||
$id_changes = 0;
|
||||
$t_changes = 0;
|
||||
/* table lock */
|
||||
if ($this->store->getLock()) {
|
||||
$con = $this->store->getDBCon();
|
||||
foreach (array('id', 's', 'o') as $id_col) {
|
||||
$tbl = $this->store->getTablePrefix() . $id_col . '2val';
|
||||
$sql = 'SELECT id, val FROM ' . $tbl . ' WHERE val LIKE "' . mysql_real_escape_string($old_uri, $con). '%"';
|
||||
if ($rs = mysql_query($sql, $con)) {
|
||||
while ($row = mysql_fetch_array($rs)) {
|
||||
$new_val = str_replace($old_uri, $new_uri, $row['val']);
|
||||
$new_id = $this->store->getTermID($new_val, $id_col , 'id');
|
||||
if (!$new_id) {/* new ns uri */
|
||||
$sub_sql = "UPDATE " . $tbl . " SET val = '" . mysql_real_escape_string($new_val, $con) . "' WHERE id = " . $row['id'];
|
||||
$sub_r = mysql_query($sub_sql, $con);
|
||||
$id_changes++;
|
||||
}
|
||||
else {
|
||||
$t_tbls = $this->store->getTables();
|
||||
foreach ($t_tbls as $t_tbl) {
|
||||
if (preg_match('/^triple_/', $t_tbl)) {
|
||||
foreach (array('s', 'p', 'o', 'o_lang_dt') as $t_col) {
|
||||
$sub_sql = "UPDATE " . $this->store->getTablePrefix() . $t_tbl . " SET " . $t_col . " = " . $new_id . " WHERE " . $t_col . " = " . $row['id'];
|
||||
$sub_r = mysql_query($sub_sql, $con);
|
||||
$t_changes += mysql_affected_rows($con);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->store->releaseLock();
|
||||
}
|
||||
return array('id_replacements' => $id_changes, 'triple_updates' => $t_changes);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
51
arc/store/ARC2_StoreInsertQueryHandler.php
Normal file
51
arc/store/ARC2_StoreInsertQueryHandler.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 RDF Store INSERT Query Handler
|
||||
author: Benjamin Nowack
|
||||
version: 2007-09-11 (Fix: empty CONSTRUCT results were not caught, which led to a GET in LOAD
|
||||
Tweak: INSERT CONSTRUCT will keep bnode ids unchanged)
|
||||
*/
|
||||
|
||||
ARC2::inc('StoreQueryHandler');
|
||||
|
||||
class ARC2_StoreInsertQueryHandler extends ARC2_StoreQueryHandler {
|
||||
|
||||
function __construct($a = '', &$caller) {/* caller has to be a store */
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreInsertQueryHandler($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* db_con */
|
||||
parent::__init();
|
||||
$this->store =& $this->caller;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function runQuery($infos, $keep_bnode_ids = 0) {
|
||||
$this->infos = $infos;
|
||||
$con = $this->store->getDBCon();
|
||||
/* insert */
|
||||
if (!$this->v('pattern', array(), $this->infos['query'])) {
|
||||
return $this->store->insert($this->infos['query']['construct_triples'], $this->infos['query']['target_graph'], $keep_bnode_ids);
|
||||
}
|
||||
else {
|
||||
$keep_bnode_ids = 1;
|
||||
ARC2::inc('StoreConstructQueryHandler');
|
||||
$h =& new ARC2_StoreConstructQueryHandler($this->a, $this->store);
|
||||
if ($sub_r = $h->runQuery($this->infos)) {
|
||||
return $this->store->insert($sub_r, $this->infos['query']['target_graph'], $keep_bnode_ids);
|
||||
}
|
||||
return array('t_count' => 0, 'load_time' => 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
439
arc/store/ARC2_StoreLoadQueryHandler.php
Normal file
439
arc/store/ARC2_StoreLoadQueryHandler.php
Normal file
@@ -0,0 +1,439 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 RDF Store LOAD Query Handler
|
||||
*
|
||||
* @author Benjamin Nowack
|
||||
* @license <http://arc.semsol.org/license>
|
||||
* @homepage <http://arc.semsol.org/>
|
||||
* @package ARC2
|
||||
* @version 2009-11-25
|
||||
*/
|
||||
|
||||
ARC2::inc('StoreQueryHandler');
|
||||
|
||||
class ARC2_StoreLoadQueryHandler extends ARC2_StoreQueryHandler {
|
||||
|
||||
function __construct($a = '', &$caller) {/* caller has to be a store */
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreLoadQueryHandler($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* db_con, store_log_inserts */
|
||||
parent::__init();
|
||||
$this->store =& $this->caller;
|
||||
$this->write_buffer_size = $this->v('store_write_buffer', 2500, $this->a);
|
||||
$this->keep_time_limit = $this->v('keep_time_limit', 0, $this->a);
|
||||
$this->split_threshold = $this->v('store_split_threshold', 0, $this->a);
|
||||
$this->has_pcre_unicode = @preg_match('/\pL/u', 'test');
|
||||
$this->strip_mb_comp_str = $this->v('store_strip_mb_comp_str', 0, $this->a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function runQuery($infos, $data = '', $keep_bnode_ids = 0) {
|
||||
$url = $infos['query']['url'];
|
||||
$graph = $infos['query']['target_graph'];
|
||||
$this->target_graph = $graph ? $this->calcURI($graph) : $this->calcURI($url);
|
||||
$this->fixed_target_graph = $graph ? $this->target_graph : '';
|
||||
$this->keep_bnode_ids = $keep_bnode_ids;
|
||||
/* reader */
|
||||
ARC2::inc('Reader');
|
||||
$reader =& new ARC2_Reader($this->a, $this);
|
||||
$reader->activate($url, $data);
|
||||
/* format detection */
|
||||
$mappings = array(
|
||||
'rdfxml' => 'RDFXML',
|
||||
'sparqlxml' => 'SPOG',
|
||||
'turtle' => 'Turtle',
|
||||
'ntriples' => 'Turtle',
|
||||
'rss' => 'RSS',
|
||||
'atom' => 'Atom',
|
||||
'n3' => 'Turtle',
|
||||
'html' => 'SemHTML',
|
||||
'sgajson' => 'SGAJSON',
|
||||
'cbjson' => 'CBJSON'
|
||||
);
|
||||
$format = $reader->getFormat();
|
||||
if (!$format || !isset($mappings[$format])) {
|
||||
return $this->addError('No loader available for "' .$url. '": ' . $format);
|
||||
}
|
||||
/* format loader */
|
||||
$suffix = 'Store' . $mappings[$format] . 'Loader';
|
||||
ARC2::inc($suffix);
|
||||
$cls = 'ARC2_' . $suffix;
|
||||
$loader =& new $cls($this->a, $this);
|
||||
$loader->setReader($reader);
|
||||
/* lock */
|
||||
if (!$this->store->getLock()) return $this->addError('Could not get lock in "runQuery"');
|
||||
$this->has_lock = 1;
|
||||
/* logging */
|
||||
$this->t_count = 0;
|
||||
$this->t_start = ARC2::mtime();
|
||||
$this->log_inserts = $this->v('store_log_inserts', 0, $this->a);
|
||||
if ($this->log_inserts) {
|
||||
@unlink("arc_insert_log.txt");
|
||||
$this->inserts = array();
|
||||
$this->insert_times = array();
|
||||
$this->t_prev = $this->t_start;
|
||||
$this->t_count_prev = 0 ;
|
||||
}
|
||||
/* load and parse */
|
||||
$this->max_term_id = $this->getMaxTermID();
|
||||
$this->max_triple_id = $this->getMaxTripleID();
|
||||
$this->column_type = $this->store->getColumnType();
|
||||
$this->createMergeTable();
|
||||
$this->term_ids = array();
|
||||
$this->triple_ids = array();
|
||||
$this->sql_buffers = array();
|
||||
$r = $loader->parse($url, $data);
|
||||
/* done */
|
||||
$this->checkSQLBuffers(1);
|
||||
if ($this->log_inserts) {
|
||||
$this->logInserts();
|
||||
}
|
||||
$this->store->releaseLock();
|
||||
$this->dropMergeTable();
|
||||
if ((rand(1, 10) == 1)) $this->store->optimizeTables();
|
||||
$t2 = ARC2::mtime();
|
||||
$dur = round($t2 - $this->t_start, 4);
|
||||
$r = array(
|
||||
't_count' => $this->t_count,
|
||||
'load_time' => $dur,
|
||||
);
|
||||
if ($this->log_inserts) {
|
||||
$r['inserts'] = $this->inserts;
|
||||
$r['insert_times'] = $this->insert_times;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
|
||||
if (!$this->has_lock) return 0;
|
||||
$type_ids = array ('uri' => '0', 'bnode' => '1' , 'literal' => '2');
|
||||
$g = $this->getTermID($this->target_graph, '0', 'id');
|
||||
$s = (($s_type == 'bnode') && !$this->keep_bnode_ids) ? '_:b' . abs(crc32($g . $s)) . '_' . (strlen($s) > 12 ? substr(substr($s, 2) , -10) : substr($s, 2)) : $s;
|
||||
$o = (($o_type == 'bnode') && !$this->keep_bnode_ids) ? '_:b' . abs(crc32($g . $o)) . '_' . (strlen($o) > 12 ? substr(substr($o, 2), -10) : substr($o, 2)) : $o;
|
||||
/* triple */
|
||||
$t = array(
|
||||
's' => $this->getTermID($s, $type_ids[$s_type], 's'),
|
||||
'p' => $this->getTermID($p, '0', 'id'),
|
||||
'o' => $this->getTermID($o, $type_ids[$o_type], 'o'),
|
||||
'o_lang_dt' => $this->getTermID($o_dt . $o_lang, $o_dt ? '0' : '2', 'id'),
|
||||
'o_comp' => $this->getOComp($o),
|
||||
's_type' => $type_ids[$s_type],
|
||||
'o_type' => $type_ids[$o_type],
|
||||
);
|
||||
$t['t'] = $this->getTripleID($t);
|
||||
if (is_array($t['t'])) {/* t exists already */
|
||||
$t['t'] = $t['t'][0];
|
||||
}
|
||||
else {
|
||||
$this->bufferTripleSQL($t);
|
||||
}
|
||||
/* g2t */
|
||||
$g2t = array('g' => $g, 't' => $t['t']);
|
||||
$this->bufferGraphSQL($g2t);
|
||||
$this->t_count++;
|
||||
/* check buffers */
|
||||
if (($this->t_count % $this->write_buffer_size) == 0) {
|
||||
$force_write = 1;
|
||||
$reset_buffers = 0;
|
||||
$refresh_lock = 0;
|
||||
$split_tables = 0;
|
||||
if (($this->t_count % ($this->write_buffer_size * 2)) == 0) {
|
||||
$reset_buffers = 1;
|
||||
if (($this->t_count % ($this->write_buffer_size * 10)) == 0) {
|
||||
$refresh_lock = 1;
|
||||
$split_tables = 1;
|
||||
}
|
||||
}
|
||||
if ($this->log_inserts) {
|
||||
$this->logInserts();
|
||||
}
|
||||
$this->checkSQLBuffers($force_write, $reset_buffers, $refresh_lock, $split_tables);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getMaxTermID() {
|
||||
$con = $this->store->getDBCon();
|
||||
$sql = '';
|
||||
foreach (array('id2val', 's2val', 'o2val') as $tbl) {
|
||||
$sql .= $sql ? ' UNION ' : '';
|
||||
$sql .= "(SELECT MAX(id) as `id` FROM " . $this->store->getTablePrefix() . $tbl . ')';
|
||||
}
|
||||
$r = 0;
|
||||
if (($rs = mysql_query($sql, $con)) && mysql_num_rows($rs)) {
|
||||
while ($row = mysql_fetch_array($rs)) {
|
||||
$r = ($r < $row['id']) ? $row['id'] : $r;
|
||||
}
|
||||
}
|
||||
return $r + 1;
|
||||
}
|
||||
|
||||
function getMaxTripleID() {
|
||||
$con = $this->store->getDBCon();
|
||||
$sql = "SELECT MAX(t) AS `id` FROM " . $this->store->getTablePrefix() . "triple";
|
||||
if (($rs = mysql_query($sql, $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
|
||||
return $row['id'] + 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function getTermID($val, $type_id, $tbl) {
|
||||
$con = $this->store->getDBCon();
|
||||
/* buffered */
|
||||
if (isset($this->term_ids[$val])) {
|
||||
if (!isset($this->term_ids[$val][$tbl])) {
|
||||
foreach (array('id', 's', 'o') as $other_tbl) {
|
||||
if (isset($this->term_ids[$val][$other_tbl])) {
|
||||
$this->term_ids[$val][$tbl] = $this->term_ids[$val][$other_tbl];
|
||||
$this->bufferIDSQL($tbl, $this->term_ids[$val][$tbl], $val, $type_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->term_ids[$val][$tbl];
|
||||
}
|
||||
/* db */
|
||||
$tbl_prefix = $this->store->getTablePrefix();
|
||||
$sub_tbls = ($tbl == 'id') ? array('id2val', 's2val', 'o2val') : ($tbl == 's' ? array('s2val', 'id2val', 'o2val') : array('o2val', 'id2val', 's2val'));
|
||||
foreach ($sub_tbls as $sub_tbl) {
|
||||
$sql = "SELECT id AS `id`, '" . $sub_tbl . "' AS `tbl` FROM " . $tbl_prefix . $sub_tbl . " WHERE val = BINARY '" . mysql_real_escape_string($val, $con) . "'";
|
||||
if (($rs = mysql_query($sql . ' LIMIT 1', $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
|
||||
$this->term_ids[$val] = array($tbl => $row['id']);
|
||||
if ($row['tbl'] != $tbl) {
|
||||
$this->bufferIDSQL($tbl, $row['id'], $val, $type_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* new */
|
||||
if (!isset($this->term_ids[$val])) {
|
||||
$this->term_ids[$val] = array($tbl => $this->max_term_id);
|
||||
$this->bufferIDSQL($tbl, $this->max_term_id, $val, $type_id);
|
||||
$this->max_term_id++;
|
||||
/* upgrade tables ? */
|
||||
if (($this->column_type == 'mediumint') && ($this->max_term_id >= 16750000)) {
|
||||
$this->store->extendColumns();
|
||||
$this->column_type = 'int';
|
||||
}
|
||||
}
|
||||
return $this->term_ids[$val][$tbl];
|
||||
}
|
||||
|
||||
function getTripleID($t) {
|
||||
$con = $this->store->getDBCon();
|
||||
$val = serialize($t);
|
||||
/* buffered */
|
||||
if (isset($this->triple_ids[$val])) {
|
||||
return array($this->triple_ids[$val]);/* hack for "don't insert this triple" */
|
||||
}
|
||||
/* db */
|
||||
$sql = "SELECT t FROM " . $this->store->getTablePrefix() . "triple WHERE
|
||||
s = " . $t['s'] . " AND p = " . $t['p'] . " AND o = " . $t['o'] . " AND o_lang_dt = " . $t['o_lang_dt'] . " AND s_type = " . $t['s_type'] . " AND o_type = " . $t['o_type'] . "
|
||||
LIMIT 1
|
||||
";
|
||||
if (($rs = mysql_query($sql, $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
|
||||
$this->triple_ids[$val] = $row['t'];/* hack for "don't insert this triple" */
|
||||
return array($row['t']);/* hack for "don't insert this triple" */
|
||||
}
|
||||
/* new */
|
||||
else {
|
||||
$this->triple_ids[$val] = $this->max_triple_id;
|
||||
$this->max_triple_id++;
|
||||
/* split tables ? */
|
||||
if ($this->split_threshold && !($this->max_triple_id % $this->split_threshold)) {
|
||||
$this->store->splitTables();
|
||||
$this->dropMergeTable();
|
||||
$this->createMergeTable();
|
||||
}
|
||||
return $this->triple_ids[$val];
|
||||
}
|
||||
}
|
||||
|
||||
function getOComp($val) {
|
||||
/* try date (e.g. 21 August 2007) */
|
||||
if (preg_match('/^[0-9]{1,2}\s+[a-z]+\s+[0-9]{4}/i', $val) && ($uts = strtotime($val)) && ($uts !== -1)) {
|
||||
return date("Y-m-d\TH:i:s", $uts);
|
||||
}
|
||||
/* xsd date (e.g. 2009-05-28T18:03:38+09:00 2009-05-28T18:03:38GMT) */
|
||||
if (preg_match('/^([0-9]{4}\-[0-9]{2}\-[0-9]{2}\T)([0-9\:]+)?([0-9\+\-\:\Z]+)?(\s*[a-z]{2,3})?$/si', $val, $m)) {
|
||||
/* yyyy-mm-dd */
|
||||
$val = $m[1];
|
||||
/* hh:ss */
|
||||
if ($m[2]) {
|
||||
$val .= $m[2];
|
||||
/* timezone offset */
|
||||
if (isset($m[3]) && ($m[3] != 'Z')) {
|
||||
$uts = strtotime(str_replace('T', ' ', $val));
|
||||
if (preg_match('/([\+\-])([0-9]{2})\:?([0-9]{2})$/', $m[3], $sub_m)) {
|
||||
$diff_mins = (3600 * ltrim($sub_m[2], '0')) + ltrim($sub_m[3], '0');
|
||||
$uts = ($m[1] == '-') ? $uts + $diff_mins : $uts - $diff_mins;
|
||||
$val = date('Y-m-d\TH:i:s\Z', $uts);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$val .= 'Z';
|
||||
}
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
/* fallback & backup w/o UTC calculation, to be removed in later revision */
|
||||
if (preg_match('/^[0-9]{4}[0-9\-\:\T\Z\+]+([a-z]{2,3})?$/i', $val)) {
|
||||
return $val;
|
||||
}
|
||||
if (is_numeric($val)) {
|
||||
$val = sprintf("%f", $val);
|
||||
if (preg_match("/([\-\+])([0-9]*)\.([0-9]*)/", $val, $m)) {
|
||||
return $m[1] . sprintf("%018s", $m[2]) . "." . sprintf("%-015s", $m[3]);
|
||||
}
|
||||
if (preg_match("/([0-9]*)\.([0-9]*)/", $val, $m)) {
|
||||
return "+" . sprintf("%018s", $m[1]) . "." . sprintf("%-015s", $m[2]);
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
/* any other string: remove tags, linebreaks etc., but keep MB-chars */
|
||||
//$val = substr(trim(preg_replace('/[\W\s]+/is', '-', strip_tags($val))), 0, 35);
|
||||
$re = $this->has_pcre_unicode ? '/[\PL\s]+/isu' : '/[\s\'\"\´\`]+/is';
|
||||
$val = trim(preg_replace($re, '-', strip_tags($val)));
|
||||
$val = function_exists("mb_substr") ? mb_substr($val, 0, 35) : substr($val, 0, 35);
|
||||
if ($this->strip_mb_comp_str) {
|
||||
$val = urldecode(preg_replace('/\%[0-9A-F]{2}/', '', urlencode($val)));
|
||||
}
|
||||
return $this->toUTF8($val);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function bufferTripleSQL($t) {
|
||||
$con = $this->store->getDBCon();
|
||||
$tbl = 'triple';
|
||||
$sql = ", ";
|
||||
if (!isset($this->sql_buffers[$tbl])) {
|
||||
$this->sql_buffers[$tbl] = "INSERT INTO " . $this->store->getTablePrefix() . $tbl . " (t, s, p, o, o_lang_dt, o_comp, s_type, o_type) VALUES";
|
||||
$sql = " ";
|
||||
}
|
||||
$this->sql_buffers[$tbl] .= $sql . "(" . $t['t'] . ", " . $t['s'] . ", " . $t['p'] . ", " . $t['o'] . ", " . $t['o_lang_dt'] . ", '" . mysql_real_escape_string($t['o_comp'], $con) . "', " . $t['s_type'] . ", " . $t['o_type'] . ")";
|
||||
}
|
||||
|
||||
function bufferGraphSQL($g2t) {
|
||||
$tbl = 'g2t';
|
||||
$sql = ", ";
|
||||
if (!isset($this->sql_buffers[$tbl])) {
|
||||
$this->sql_buffers[$tbl] = "INSERT IGNORE INTO " . $this->store->getTablePrefix() . $tbl . " (g, t) VALUES";
|
||||
$sql = " ";
|
||||
}
|
||||
$this->sql_buffers[$tbl] .= $sql . "(" . $g2t['g'] . ", " . $g2t['t'] . ")";
|
||||
}
|
||||
|
||||
function bufferIDSQL($tbl, $id, $val, $val_type) {
|
||||
$con = $this->store->getDBCon();
|
||||
$tbl = $tbl . '2val';
|
||||
$sql = ", ";
|
||||
if (!isset($this->sql_buffers[$tbl])) {
|
||||
$cols = ($tbl == 'id2val') ? "id, val, val_type" : "id, val";
|
||||
$this->sql_buffers[$tbl] = "INSERT IGNORE INTO " . $this->store->getTablePrefix() . $tbl . "(" . $cols . ") VALUES";
|
||||
$sql = " ";
|
||||
}
|
||||
if ($tbl == 'id2val') {
|
||||
$sql .= "(" . $id . ", '" . mysql_real_escape_string($val, $con) . "', " . $val_type . ")";
|
||||
}
|
||||
else {
|
||||
$sql .= "(" . $id . ", '" . mysql_real_escape_string($val, $con) . "')";
|
||||
}
|
||||
$this->sql_buffers[$tbl] .= $sql;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function checkSQLBuffers($force_write = 0, $reset_id_buffers = 0, $refresh_lock = 0, $split_tables = 0) {
|
||||
$con = $this->store->getDBCon();
|
||||
if (!$this->keep_time_limit) @set_time_limit($this->v('time_limit', 60, $this->a));
|
||||
foreach (array('triple', 'g2t', 'id2val', 's2val', 'o2val') as $tbl) {
|
||||
$buffer_size = isset($this->sql_buffers[$tbl]) ? 1 : 0;
|
||||
if ($buffer_size && $force_write) {
|
||||
$t1 = ARC2::mtime();
|
||||
mysql_query($this->sql_buffers[$tbl], $con);
|
||||
/* table error */
|
||||
if ($er = mysql_error($con)) {
|
||||
$this->autoRepairTable($er, $con);
|
||||
}
|
||||
unset($this->sql_buffers[$tbl]);
|
||||
if ($this->log_inserts) {
|
||||
$t2 = ARC2::mtime();
|
||||
$this->inserts[$tbl] = $this->v($tbl, 0, $this->inserts) + max(0, mysql_affected_rows($con));
|
||||
$dur = round($t2 - $t1, 4);
|
||||
$this->insert_times[$tbl] = isset($this->insert_times[$tbl]) ? $this->insert_times[$tbl] : array('min' => $dur, 'max' => $dur, 'sum' => $dur);
|
||||
$this->insert_times[$tbl] = array('min' => min($dur, $this->insert_times[$tbl]['min']), 'max' => max($dur, $this->insert_times[$tbl]['max']), 'sum' => $dur + $this->insert_times[$tbl]['sum']);
|
||||
}
|
||||
/* reset term id buffers */
|
||||
if ($reset_id_buffers) {
|
||||
$this->term_ids = array();
|
||||
$this->triple_ids = array();
|
||||
}
|
||||
/* refresh lock */
|
||||
if ($refresh_lock) {
|
||||
$this->store->releaseLock();
|
||||
$this->has_lock = 0;
|
||||
sleep(1);
|
||||
if (!$this->store->getLock(5)) return $this->addError('Could not re-obtain lock in "checkSQLBuffers"');
|
||||
$this->has_lock = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function autoRepairTable($er, $con) {
|
||||
$this->addError('MySQL error: ' . $er);
|
||||
if (preg_match('/Table \'[^\']+\/([a-z0-9\_\-]+)\' .*(crashed|repair)/i', $er, $m)) {
|
||||
$rs = mysql_query('REPAIR TABLE ' . rawurlencode($m[1]), $con);
|
||||
$msg = $rs ? mysql_fetch_array($rs) : array();
|
||||
if ($this->v('Msg_type', 'error', $msg) == 'error') {
|
||||
/* auto-reset */
|
||||
if ($this->v('store_reset_on_table_crash', 0, $this->a)) {
|
||||
$this->store->drop();
|
||||
$this->store->setUp();
|
||||
}
|
||||
else {
|
||||
$er = $this->v('Msg_text', 'unknown error', $msg);
|
||||
$this->addError('Auto-repair failed on ' . rawurlencode($m[1]) . ': ' . $er);
|
||||
}
|
||||
//die("Fatal errors: \n" . print_r($this->getErrors(), 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* speed log */
|
||||
|
||||
function logInserts() {
|
||||
$t_start = $this->t_start;
|
||||
$t_prev = $this->t_prev;
|
||||
$t_now = ARC2::mtime();
|
||||
$tc_prev = $this->t_count_prev;
|
||||
$tc_now = $this->t_count;
|
||||
$tc_diff = $tc_now - $tc_prev;
|
||||
|
||||
$dur_full = $t_now - $t_start;
|
||||
$dur_diff = $t_now - $t_prev;
|
||||
|
||||
$speed_full = round($tc_now / $dur_full);
|
||||
$speed_now = round($tc_diff / $dur_diff);
|
||||
|
||||
$r = $tc_diff . ' in ' . round($dur_diff, 5) . ' = ' . $speed_now . ' t/s (' .$tc_now. ' in ' . round($dur_full, 5). ' = ' . $speed_full . ' t/s )';
|
||||
$fp = @fopen("arc_insert_log.txt", "a");
|
||||
@fwrite($fp, $r . "\r\n");
|
||||
@fclose($fp);
|
||||
|
||||
$this->t_prev = $t_now;
|
||||
$this->t_count_prev = $tc_now;
|
||||
}
|
||||
|
||||
}
|
||||
87
arc/store/ARC2_StoreQueryHandler.php
Normal file
87
arc/store/ARC2_StoreQueryHandler.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 RDF Store Query Handler
|
||||
author: Benjamin Nowack
|
||||
version: 2009-02-13 (Tweak: removed cid parameter in getTermID() method)
|
||||
*/
|
||||
|
||||
ARC2::inc('Class');
|
||||
|
||||
class ARC2_StoreQueryHandler extends ARC2_Class {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreQueryHandler($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* db_con */
|
||||
parent::__init();
|
||||
$this->xsd = 'http://www.w3.org/2001/XMLSchema#';
|
||||
$this->allow_extension_functions = $this->v('store_allow_extension_functions', 1, $this->a);
|
||||
$this->handler_type = '';
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTermID($val, $term = '') {
|
||||
return $this->store->getTermID($val, $term);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTripleTable() {
|
||||
$r = $this->store->getTablePrefix() . 'triple';
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function createMergeTable() {
|
||||
$split_ps = $this->store->getSetting('split_predicates', array());
|
||||
if (!$split_ps) return 1;
|
||||
$this->mrg_table_id = 'MRG_' . $this->store->getTablePrefix() . crc32(uniqid(rand()));
|
||||
$con = $this->store->getDBCon();
|
||||
mysql_query("FLUSH TABLES", $con);
|
||||
$indexes = $this->v('store_indexes', array('sp (s,p)', 'os (o,s)', 'po (p,o)'), $this->a);
|
||||
$index_code = $indexes ? 'KEY ' . join(', KEY ', $indexes) . ', ' : '';
|
||||
$prefix = $this->store->getTablePrefix();
|
||||
$sql = "
|
||||
CREATE TEMPORARY TABLE IF NOT EXISTS " . $prefix . "triple_all (
|
||||
t mediumint UNSIGNED NOT NULL,
|
||||
s mediumint UNSIGNED NOT NULL,
|
||||
p mediumint UNSIGNED NOT NULL,
|
||||
o mediumint UNSIGNED NOT NULL,
|
||||
o_lang_dt mediumint UNSIGNED NOT NULL,
|
||||
o_comp char(35) NOT NULL, /* normalized value for ORDER BY operations */
|
||||
s_type tinyint(1) NOT NULL default 0, /* uri/bnode => 0/1 */
|
||||
o_type tinyint(1) NOT NULL default 0, /* uri/bnode/literal => 0/1/2 */
|
||||
misc tinyint(1) NOT NULL default 0, /* temporary flags */
|
||||
UNIQUE KEY (t), " . $index_code . " KEY (misc)
|
||||
)
|
||||
";
|
||||
$v = $this->store->getDBVersion();
|
||||
$sql .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
|
||||
$sql .= "=MERGE UNION=(" . $prefix . "triple" ;
|
||||
foreach ($split_ps as $pos => $p) {
|
||||
$sql .= ',' . $prefix . 'triple_' . abs(crc32($p));
|
||||
}
|
||||
$sql .= ")";
|
||||
//$sql .= ($v >= '04-00-00') ? " CHARACTER SET utf8" : "";
|
||||
//$sql .= ($v >= '04-01-00') ? " COLLATE utf8_unicode_ci" : "";
|
||||
//echo $sql;
|
||||
return mysql_query($sql, $con);
|
||||
}
|
||||
|
||||
function dropMergeTable() {
|
||||
$sql = "DROP TABLE IF EXISTS " . $this->store->getTablePrefix() . "triple_all";
|
||||
//echo $sql;
|
||||
return mysql_query($sql, $this->store->getDBCon());
|
||||
}
|
||||
|
||||
}
|
||||
36
arc/store/ARC2_StoreRDFXMLLoader.php
Normal file
36
arc/store/ARC2_StoreRDFXMLLoader.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Store RDF/XML Loader
|
||||
author: Benjamin Nowack
|
||||
version: 2007-08-21
|
||||
*/
|
||||
|
||||
ARC2::inc('RDFXMLParser');
|
||||
|
||||
class ARC2_StoreRDFXMLLoader extends ARC2_RDFXMLParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreRDFXMLLoader($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
|
||||
$this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
|
||||
$this->t_count++;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
36
arc/store/ARC2_StoreRSSLoader.php
Normal file
36
arc/store/ARC2_StoreRSSLoader.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Store RSS(2) Loader
|
||||
author: Benjamin Nowack
|
||||
version: 2008-06-28 (Tweak: adjusted to normalized "literal" type)
|
||||
*/
|
||||
|
||||
ARC2::inc('RSSParser');
|
||||
|
||||
class ARC2_StoreRSSLoader extends ARC2_RSSParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreRSSLoader($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function addT($t) {
|
||||
$this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
|
||||
$this->t_count++;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
40
arc/store/ARC2_StoreSGAJSONLoader.php
Normal file
40
arc/store/ARC2_StoreSGAJSONLoader.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Store SG API JSON Loader
|
||||
author: Benjamin Nowack
|
||||
version: 2008-07-15
|
||||
*/
|
||||
|
||||
ARC2::inc('SGAJSONParser');
|
||||
|
||||
class ARC2_StoreSGAJSONLoader extends ARC2_SGAJSONParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreSGAJSONLoader($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function done() {
|
||||
$this->extractRDF();
|
||||
}
|
||||
|
||||
function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
|
||||
$this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
|
||||
$this->t_count++;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
42
arc/store/ARC2_StoreSPOGLoader.php
Normal file
42
arc/store/ARC2_StoreSPOGLoader.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Store SPOG Loader
|
||||
author: Morten Høybye Frederiksen / Benjamin Nowack
|
||||
version: 2008-07-02
|
||||
*/
|
||||
|
||||
ARC2::inc('SPOGParser');
|
||||
|
||||
class ARC2_StoreSPOGLoader extends ARC2_SPOGParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreSPOGLoader($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '', $g) {
|
||||
if (!($s && $p && $o)) return 0;
|
||||
if (!$g) $g = $this->caller->target_graph;
|
||||
if ($this->caller->fixed_target_graph) $g = $this->caller->fixed_target_graph;
|
||||
$prev_g = $this->caller->target_graph;
|
||||
$this->caller->target_graph = $g;
|
||||
$this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
|
||||
$this->caller->target_graph = $prev_g;
|
||||
$this->t_count++;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
1755
arc/store/ARC2_StoreSelectQueryHandler.php
Normal file
1755
arc/store/ARC2_StoreSelectQueryHandler.php
Normal file
File diff suppressed because it is too large
Load Diff
40
arc/store/ARC2_StoreSemHTMLLoader.php
Normal file
40
arc/store/ARC2_StoreSemHTMLLoader.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Store SemHTML Loader
|
||||
author: Benjamin Nowack
|
||||
version: 2008-06-28 (Tweak: adjusted to normalized "literal" type)
|
||||
*/
|
||||
|
||||
ARC2::inc('SemHTMLParser');
|
||||
|
||||
class ARC2_StoreSemHTMLLoader extends ARC2_SemHTMLParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreSemHTMLLoader($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function done() {
|
||||
$this->extractRDF();
|
||||
}
|
||||
|
||||
function addT($t) {
|
||||
$this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
|
||||
$this->t_count++;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
287
arc/store/ARC2_StoreTableManager.php
Normal file
287
arc/store/ARC2_StoreTableManager.php
Normal file
@@ -0,0 +1,287 @@
|
||||
<?php
|
||||
/**
|
||||
* ARC2 RDF Store Table Manager
|
||||
*
|
||||
* @license http://arc.semsol.org/license
|
||||
* @author Benjamin Nowack
|
||||
* @version 2009-09-07 Tweak: store_engine_type is a config option
|
||||
*
|
||||
*/
|
||||
|
||||
ARC2::inc('Store');
|
||||
|
||||
class ARC2_StoreTableManager extends ARC2_Store {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreTableManager($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {/* db_con */
|
||||
parent::__init();
|
||||
$this->engine_type = $this->v('store_engine_type', 'MyISAM', $this->a);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function getTableOptionsCode() {
|
||||
$v = $this->getDBVersion();
|
||||
$r = "";
|
||||
$r .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
|
||||
$r .= "=" . $this->engine_type;
|
||||
$r .= ($v >= '04-00-00') ? " CHARACTER SET utf8" : "";
|
||||
$r .= ($v >= '04-01-00') ? " COLLATE utf8_unicode_ci" : "";
|
||||
$r .= " DELAY_KEY_WRITE = 1";
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function createTables() {
|
||||
$con = $this->getDBCon();
|
||||
if(!$this->createTripleTable()) {
|
||||
return $this->addError('Could not create "triple" table (' . mysql_error($con) . ').');
|
||||
}
|
||||
if(!$this->createG2TTable()) {
|
||||
return $this->addError('Could not create "g2t" table (' . mysql_error($con) . ').');
|
||||
}
|
||||
if(!$this->createID2ValTable()) {
|
||||
return $this->addError('Could not create "id2val" table (' . mysql_error($con) . ').');
|
||||
}
|
||||
if(!$this->createS2ValTable()) {
|
||||
return $this->addError('Could not create "s2val" table (' . mysql_error($con) . ').');
|
||||
}
|
||||
if(!$this->createO2ValTable()) {
|
||||
return $this->addError('Could not create "o2val" table (' . mysql_error($con) . ').');
|
||||
}
|
||||
if(!$this->createSettingTable()) {
|
||||
return $this->addError('Could not create "setting" table (' . mysql_error($con) . ').');
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function createTripleTable($suffix = 'triple') {
|
||||
/* keep in sync with merge def in StoreQueryHandler ! */
|
||||
$indexes = $this->v('store_indexes', array('sp (s,p)', 'os (o,s)', 'po (p,o)'), $this->a);
|
||||
$index_code = $indexes ? 'KEY ' . join(', KEY ', $indexes) . ', ' : '';
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . $suffix . " (
|
||||
t mediumint UNSIGNED NOT NULL,
|
||||
s mediumint UNSIGNED NOT NULL,
|
||||
p mediumint UNSIGNED NOT NULL,
|
||||
o mediumint UNSIGNED NOT NULL,
|
||||
o_lang_dt mediumint UNSIGNED NOT NULL,
|
||||
o_comp char(35) NOT NULL, /* normalized value for ORDER BY operations */
|
||||
s_type tinyint(1) NOT NULL default 0, /* uri/bnode => 0/1 */
|
||||
o_type tinyint(1) NOT NULL default 0, /* uri/bnode/literal => 0/1/2 */
|
||||
misc tinyint(1) NOT NULL default 0, /* temporary flags */
|
||||
UNIQUE KEY (t), " . $index_code . " KEY (misc)
|
||||
) ". $this->getTableOptionsCode() . "
|
||||
";
|
||||
return mysql_query($sql, $this->getDBCon());
|
||||
}
|
||||
|
||||
function extendTripleTableColumns($suffix = 'triple') {
|
||||
$sql = "
|
||||
ALTER TABLE " . $this->getTablePrefix() . $suffix . "
|
||||
MODIFY t int(10) UNSIGNED NOT NULL,
|
||||
MODIFY s int(10) UNSIGNED NOT NULL,
|
||||
MODIFY p int(10) UNSIGNED NOT NULL,
|
||||
MODIFY o int(10) UNSIGNED NOT NULL,
|
||||
MODIFY o_lang_dt int(10) UNSIGNED NOT NULL
|
||||
";
|
||||
return mysql_query($sql, $this->getDBCon());
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function createG2TTable() {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "g2t (
|
||||
g mediumint UNSIGNED NOT NULL,
|
||||
t mediumint UNSIGNED NOT NULL,
|
||||
UNIQUE KEY gt (g,t), KEY tg (t,g)
|
||||
) ". $this->getTableOptionsCode() . "
|
||||
";
|
||||
return mysql_query($sql, $this->getDBCon());
|
||||
}
|
||||
|
||||
function extendG2tTableColumns($suffix = 'g2t') {
|
||||
$sql = "
|
||||
ALTER TABLE " . $this->getTablePrefix() . $suffix . "
|
||||
MODIFY g int(10) UNSIGNED NOT NULL,
|
||||
MODIFY t int(10) UNSIGNED NOT NULL
|
||||
";
|
||||
return mysql_query($sql, $this->getDBCon());
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function createID2ValTable() {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "id2val (
|
||||
id mediumint UNSIGNED NOT NULL,
|
||||
misc tinyint(1) NOT NULL default 0,
|
||||
val text NOT NULL,
|
||||
val_type tinyint(1) NOT NULL default 0, /* uri/bnode/literal => 0/1/2 */
|
||||
UNIQUE KEY (id,val_type), KEY v (val(64))
|
||||
) ". $this->getTableOptionsCode() . "
|
||||
";
|
||||
return mysql_query($sql, $this->getDBCon());
|
||||
}
|
||||
|
||||
function extendId2valTableColumns($suffix = 'id2val') {
|
||||
$sql = "
|
||||
ALTER TABLE " . $this->getTablePrefix() . $suffix . "
|
||||
MODIFY id int(10) UNSIGNED NOT NULL
|
||||
";
|
||||
return mysql_query($sql, $this->getDBCon());
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function createS2ValTable() {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "s2val (
|
||||
id mediumint UNSIGNED NOT NULL,
|
||||
misc tinyint(1) NOT NULL default 0,
|
||||
val text NOT NULL,
|
||||
UNIQUE KEY (id), KEY v (val(64))
|
||||
) ". $this->getTableOptionsCode() . "
|
||||
";
|
||||
return mysql_query($sql, $this->getDBCon());
|
||||
}
|
||||
|
||||
function extendS2valTableColumns($suffix = 's2val') {
|
||||
$sql = "
|
||||
ALTER TABLE " . $this->getTablePrefix() . $suffix . "
|
||||
MODIFY id int(10) UNSIGNED NOT NULL
|
||||
";
|
||||
return mysql_query($sql, $this->getDBCon());
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function createO2ValTable() {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "o2val (
|
||||
id mediumint UNSIGNED NOT NULL,
|
||||
misc tinyint(1) NOT NULL default 0,
|
||||
val text NOT NULL,
|
||||
UNIQUE KEY (id), KEY v (val(64))
|
||||
) ". $this->getTableOptionsCode() . "
|
||||
";
|
||||
return mysql_query($sql, $this->getDBCon());
|
||||
}
|
||||
|
||||
function extendO2valTableColumns($suffix = 'o2val') {
|
||||
$sql = "
|
||||
ALTER TABLE " . $this->getTablePrefix() . $suffix . "
|
||||
MODIFY id int(10) UNSIGNED NOT NULL
|
||||
";
|
||||
return mysql_query($sql, $this->getDBCon());
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function createSettingTable() {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "setting (
|
||||
k char(32) NOT NULL,
|
||||
val text NOT NULL,
|
||||
UNIQUE KEY (k)
|
||||
) ". $this->getTableOptionsCode() . "
|
||||
";
|
||||
return mysql_query($sql, $this->getDBCon());
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function extendColumns() {
|
||||
$con = $this->getDBCon();
|
||||
$tbl_prefix = $this->getTablePrefix();
|
||||
$tbls = $this->getTables();
|
||||
foreach ($tbls as $suffix) {
|
||||
if (preg_match('/^(triple|g2t|id2val|s2val|o2val)/', $suffix, $m)) {
|
||||
$mthd = 'extend' . ucfirst($m[1]) . 'TableColumns';
|
||||
$this->$mthd($suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function splitTables() {
|
||||
$old_ps = $this->getSetting('split_predicates', array());
|
||||
$new_ps = $this->retrieveSplitPredicates();
|
||||
$add_ps = array_diff($new_ps, $old_ps);
|
||||
$del_ps = array_diff($old_ps, $new_ps);
|
||||
$final_ps = array();
|
||||
foreach ($del_ps as $p) {
|
||||
if (!$this->unsplitPredicate($p)) $final_ps[] = $p;
|
||||
}
|
||||
foreach ($add_ps as $p) {
|
||||
if ($this->splitPredicate($p)) $final_ps[] = $p;
|
||||
}
|
||||
$this->setSetting('split_predicates', $new_ps);
|
||||
}
|
||||
|
||||
function unsplitPredicate($p) {
|
||||
$suffix = 'triple_' . abs(crc32($p));
|
||||
$old_tbl = $this->getTablePrefix() . $suffix;
|
||||
$new_tbl = $this->getTablePrefix() . 'triple';
|
||||
$p_id = $this->getTermID($p, 'p');
|
||||
$con = $this->getDBCon();
|
||||
$sql = '
|
||||
INSERT IGNORE INTO ' . $new_tbl .'
|
||||
SELECT * FROM ' . $old_tbl . ' WHERE ' . $old_tbl . '.p = ' . $p_id . '
|
||||
';
|
||||
if ($rs = mysql_query($sql, $con)) {
|
||||
mysql_query('DROP TABLE ' . $old_tbl, $con);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function splitPredicate($p) {
|
||||
$suffix = 'triple_' . abs(crc32($p));
|
||||
$this->createTripleTable($suffix);
|
||||
$old_tbl = $this->getTablePrefix() . 'triple';
|
||||
$new_tbl = $this->getTablePrefix() . $suffix;
|
||||
$p_id = $this->getTermID($p, 'p');
|
||||
$con = $this->getDBCon();
|
||||
$sql = '
|
||||
INSERT IGNORE INTO ' . $new_tbl .'
|
||||
SELECT * FROM ' . $old_tbl . ' WHERE ' . $old_tbl . '.p = ' . $p_id . '
|
||||
';
|
||||
if ($rs = mysql_query($sql, $con)) {
|
||||
mysql_query('DELETE FROM ' . $old_tbl . ' WHERE ' . $old_tbl . '.p = ' . $p_id, $con);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
mysql_query('DROP TABLE ' . $new_tbl, $con);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function retrieveSplitPredicates() {
|
||||
$r = $this->split_predicates;
|
||||
$limit = $this->max_split_tables - count($r);
|
||||
$q = 'SELECT ?p COUNT(?p) AS ?pc WHERE { ?s ?p ?o } GROUP BY ?p ORDER BY DESC(?pc) LIMIT ' . $limit;
|
||||
$rows = $this->query($q, 'rows');
|
||||
foreach ($rows as $row) {
|
||||
$r[] = $row['p'];
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
36
arc/store/ARC2_StoreTurtleLoader.php
Normal file
36
arc/store/ARC2_StoreTurtleLoader.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/*
|
||||
homepage: http://arc.semsol.org/
|
||||
license: http://arc.semsol.org/license
|
||||
|
||||
class: ARC2 Store Turtle Loader
|
||||
author: Benjamin Nowack
|
||||
version: 2008-06-28 (Tweak: adjusted to normalized "literal" type)
|
||||
*/
|
||||
|
||||
ARC2::inc('TurtleParser');
|
||||
|
||||
class ARC2_StoreTurtleLoader extends ARC2_TurtleParser {
|
||||
|
||||
function __construct($a = '', &$caller) {
|
||||
parent::__construct($a, $caller);
|
||||
}
|
||||
|
||||
function ARC2_StoreTurtleLoader($a = '', &$caller) {
|
||||
$this->__construct($a, $caller);
|
||||
}
|
||||
|
||||
function __init() {
|
||||
parent::__init();
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
function addT($t) {
|
||||
$this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
|
||||
$this->t_count++;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
}
|
||||
8
assumptions.html
Normal file
8
assumptions.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html><body>
|
||||
|
||||
<h2><a name="AqueductDocumentation-1.2-Assumptions"></a>Assumptions</h2>
|
||||
|
||||
<p>This document assumes that the reader has a basic knowledge of RDF. The reader should have a thorough understanding of URIs and how they can represent real-world entities. The reader should also understand how RDF statements can represent knowledge about real-world entities through their predicates and objects.</p>
|
||||
|
||||
<p>The reader should also be familiar with Mediawiki administration, including the installation of extensions and the concept of Mediawiki namespaces. </p>
|
||||
</body></html>
|
||||
27
documentation.html
Normal file
27
documentation.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<html><body>
|
||||
|
||||
<h2>Aqueduct</h2>
|
||||
<p>Aqueduct is a collection of software packages to facilitate the rapid development of applications using semantic web technology. Aqueduct provides a set of "building blocks" for creating applications where users can visualize, create, search, and mine semantic data, using open standards such as RDF.</p>
|
||||
|
||||
<p>Aqueduct is currently composed of several software packages:</p>
|
||||
|
||||
<p>Aqueduct extension for Mediawiki: The Aqueduct extension for Mediawiki that provides several services that allow external semantic data sources (such as Blackbook) to be integrated with a wiki. The Aqueduct plugin is distinct from Semantic Mediawiki (another third-party Mediawiki extension.)</p>
|
||||
|
||||
<p>Aqueduct API for Mediawiki: The Aqueduct API allows external programs to read and write semantic data from multiple sources in a machine-readable format by using the wiki as a "hub" or "router" for the data. This allows for the construction of a software system that leverages a wiki in conjunction with other tools or agents, without ending up with multiple inconsistent views of the data.</p>
|
||||
|
||||
<p>Aqueduct (Cistern) widgets for Mediawiki: The Cistern widgets allow for semantic data to be visualized from within wiki pages. Wiki pages with Cistern widgets serve a dual purpose -- they act as traditional wiki pages while simultaneously displaying "widget" controls that allow the user to browse semantic data that is related to the page that they are on.</p>
|
||||
|
||||
<p>Siphon: The Siphon allows for data authored in Semantic Mediawiki to be mirrored in Blackbook. This facilitates the creation of systems that combine the semantic authorship capabilities of Semantic Mediawiki with the data integration and analysis capabilities of Blackbook.</p>
|
||||
|
||||
<p>The Aqueduct documentation contains the following pages:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="assumptions.html">Assumptions</a></li>
|
||||
<li><a href="aqueductinstallation.html">Installation of Aqueduct</a></li>
|
||||
<li><a href="aqueduct.html">Basic uses of Aqueduct</a></li>
|
||||
<li><a href="aqueductadvanced.html">Advanced uses of Aqueduct</a></li>
|
||||
<li><a href="aqueductapi.html">Aqueduct API</a></li>
|
||||
<li><a href="siphon.html">Siphon</a></li>
|
||||
</ul>
|
||||
|
||||
</body></html>
|
||||
206
includes/ApiAqueduct.php
Normal file
206
includes/ApiAqueduct.php
Normal file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
require_once('extensions/AqueductExtension/includes/AqueductDbCalls.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterface.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceBlackbook.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceTest.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceEmbedded.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductUtility.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceBlackbook28.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceBlackbook30.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceMemcached.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceArc2.php');
|
||||
require_once('extensions/AqueductExtension/arc/ARC2.php');
|
||||
|
||||
class ApiAqueduct extends ApiBase
|
||||
{
|
||||
public function __construct($main, $action)
|
||||
{
|
||||
parent :: __construct($main, $action);
|
||||
}
|
||||
|
||||
public function execute()
|
||||
{
|
||||
aqProfile("aq");
|
||||
$params = $this->extractRequestParams();
|
||||
$t = Title::newFromText($params['subject']);
|
||||
$result = $this->getForest($t);
|
||||
//The result "forest" is a set of named ARC2 index structures
|
||||
//We will have to convert each one to RDF/JSON
|
||||
aqProfile("arc");
|
||||
$ser = ARC2::getRDFJSONSerializer();
|
||||
aqProfile("aq");
|
||||
foreach ($result as $key=>$value)
|
||||
{
|
||||
aqProfile("arcJSONRDFser");
|
||||
$sertriples = $ser->getSerializedIndex($value);
|
||||
aqProfile("aq");
|
||||
$this->getResult()->addValue(null, $key, json_decode($sertriples));
|
||||
}
|
||||
//If profiling is on, dump the profiling data with the RDF-JSON structure
|
||||
global $wgAqueductProfile,$aqProfileData;
|
||||
if ($wgAqueductProfile === TRUE)
|
||||
{
|
||||
$this->getResult()->addValue(null, "profiling", $aqProfileData);
|
||||
}
|
||||
aqProfile("mw");
|
||||
}
|
||||
|
||||
protected function getForest($title)
|
||||
{
|
||||
global $wgAqueductDataAdded,$wgAqueductQueryAdded;
|
||||
$allforests = array();
|
||||
//Someone is requesting the data (forest) associated with the title $title
|
||||
//This function will return the forest
|
||||
if ($title->getArticleID() != 0)
|
||||
{
|
||||
//A wiki page is associated with the title. This page could have data inclusion tags (addData tags), meaning that
|
||||
//this function should combine RDF from multiple places
|
||||
//Parse the wiki page to see if it has any addData tags
|
||||
$wgAqueductDataAdded = array();
|
||||
$wgAqueductQueryAdded = array();
|
||||
$p = new Parser();
|
||||
wfAqueductSetParserHooks($p);
|
||||
$p->disableCache();
|
||||
$po = new ParserOptions();
|
||||
$a = new Article($title);
|
||||
$p->parse($a->getRawText(),$title,$po);
|
||||
$morepages = $wgAqueductDataAdded;
|
||||
$queryrows = $wgAqueductQueryAdded;
|
||||
unset($GLOBALS['wgAqueductDataAdded']);
|
||||
unset($GLOBALS['wgAqueductQueryAdded']);
|
||||
//At this point, $morepages has the titles specified in any addData tags
|
||||
foreach($morepages as $othertitle)
|
||||
{
|
||||
//There was an addData tag on the page associated with $title
|
||||
//Merge this title's data with the other title's data
|
||||
array_push($allforests, $this->getForest($othertitle));
|
||||
}
|
||||
//At this point, $queryrows has a collection of advanced row objects specified by any addQuery tags
|
||||
foreach($queryrows as $inlinequery)
|
||||
{
|
||||
//Merge this query's data with any other data
|
||||
array_push($allforests, $this->getForestFromRow(NULL,AqueductUtility::getBasicRowFromAdvancedRow($inlinequery),$inlinequery));
|
||||
}
|
||||
}
|
||||
|
||||
//Also add the default model, if it exists
|
||||
$defaultmodel = $this->getForestDefaultModel($title,count($allforests)>0);
|
||||
if ($defaultmodel !== NULL)
|
||||
{
|
||||
array_push($allforests, $defaultmodel);
|
||||
}
|
||||
|
||||
//Merge the forests and return
|
||||
//Keep track of a disambiguation value that we will prepend to anything that starts with an underscore
|
||||
//(trees starting with an underscore must never be merged with other trees, even if the name is the same.
|
||||
//any name collisions are only due to autogeneration)
|
||||
$blanktreenumber = 0;
|
||||
$result = array();
|
||||
foreach ($allforests as $forest)
|
||||
{
|
||||
$blanktreenumber++;
|
||||
foreach ($forest as $treename => $tree)
|
||||
{
|
||||
if (substr($treename,0,1) == '_')
|
||||
{
|
||||
$n = '_' . $blanktreenumber . $treename;
|
||||
}
|
||||
else
|
||||
{
|
||||
$n = $treename;
|
||||
}
|
||||
if (isset($result[$n]))
|
||||
{
|
||||
//Tree already exists. Merge triples from two queries into a merged tree for display
|
||||
aqProfile("arcMergeForests");
|
||||
$result[$n] = ARC2::getMergedIndex($tree,$result[$n]);
|
||||
aqProfile("aq");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Tree does not exist yet
|
||||
$result[$n] = $tree;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function getForestFromRow($title, $basicrow, $advancedrow)
|
||||
{
|
||||
if (!isset($title) && $advancedrow === NULL)
|
||||
{
|
||||
throw new Exception('Specify a title to materialize.');
|
||||
}
|
||||
|
||||
$interface = AqueductUtility::getInterfaceForRow($basicrow);
|
||||
if ($advancedrow!==NULL)
|
||||
{
|
||||
$result = $interface->advancedOperation($title,$advancedrow);
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = $interface->materialize($title);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function getForestDefaultModel($t, $ignoreMissingModel = FALSE)
|
||||
{
|
||||
$basicrow = NULL;
|
||||
$advancedrow = NULL;
|
||||
AqueductUtility::getRowsForAqueductTitle($t, $basicrow, $advancedrow);
|
||||
if ($basicrow === NULL)
|
||||
{
|
||||
//Not a basic or advanced query
|
||||
if ($ignoreMissingModel)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
throw new Exception('No semantic data is available for '. $params['subject'] . ' (namespace ' . $ns . ').');
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->getForestFromRow($t, $basicrow, $advancedrow);
|
||||
}
|
||||
}
|
||||
|
||||
public function getAllowedParams()
|
||||
{
|
||||
return array ('subject' => null);
|
||||
}
|
||||
|
||||
public function getParamDescription()
|
||||
{
|
||||
return array ('subject' => 'RDF subject or query that you want to perform the action on, formatted as a wiki title.');
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return array('Aqueduct RDF data API.');
|
||||
}
|
||||
|
||||
public function getVersion()
|
||||
{
|
||||
return __CLASS__ . '1.0i';
|
||||
}
|
||||
}
|
||||
|
||||
99
includes/ApiAqueductSet.php
Normal file
99
includes/ApiAqueductSet.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
require_once('extensions/AqueductExtension/includes/AqueductDbCalls.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterface.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceBlackbook.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceTest.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceEmbedded.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceBlackbook28.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceBlackbook30.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceMemcached.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceArc2.php');
|
||||
require_once('extensions/AqueductExtension/arc/ARC2.php');
|
||||
|
||||
class ApiAqueductSet extends ApiBase
|
||||
{
|
||||
public function __construct($main, $action)
|
||||
{
|
||||
parent :: __construct($main, $action);
|
||||
}
|
||||
|
||||
public function execute()
|
||||
{
|
||||
aqProfile("aq");
|
||||
$params = $this->extractRequestParams();
|
||||
|
||||
// If subject is a title, create the object, otherwise, use uritotitle.
|
||||
if (!isset($params['subjecttype']) || $params['subjecttype']== 'page')
|
||||
{
|
||||
$t = Title::newFromText($params['subject']);
|
||||
}
|
||||
else if ($params['subjecttype']== 'uri')
|
||||
{
|
||||
$t = Title::newFromText(AqueductInterface::uriToTitle($params['subject']));
|
||||
//Here we could end up with a title in the Unknown namespace. If we did, this will cause a crash soon
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Invalid subject type');
|
||||
}
|
||||
$result = $this->doHardSet($t,$params['predicateURI'], $params['object'], $params['objecttype']);
|
||||
aqProfile("mw");
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function doHardSet($title, $pred, $obj, $objtype)
|
||||
{
|
||||
$basicrow = NULL;
|
||||
$advancedrow = NULL;
|
||||
AqueductUtility::getRowsForAqueductTitle($title, $basicrow, $advancedrow);
|
||||
if ($basicrow===NULL || $advancedrow!==NULL)
|
||||
{
|
||||
//Not a valid hard set
|
||||
throw new Exception('The namespace => datasource entry for the hard set was not found.');
|
||||
}
|
||||
$interface = AqueductUtility::getInterfaceForRow($basicrow);
|
||||
$interface->hardSet($title, $pred, $obj, $objtype);
|
||||
}
|
||||
|
||||
public function getAllowedParams()
|
||||
{
|
||||
return array ('subject' => null, 'subjecttype' => 'page', 'predicateURI' => null, 'object' => null, 'objecttype' => 'literal');
|
||||
}
|
||||
|
||||
public function getParamDescription()
|
||||
{
|
||||
return array ('subject' => 'RDF subject to add the triple to. Formatted only as a wiki title for now.',
|
||||
'subjecttype' => 'RDF subject type, either "page" for a wiki title (default), or "uri" for a datasource uri. Currently ignored until subject uri functionality is added.',
|
||||
'predicateURI' => 'URI to the RDF predicate to replace the triple for.',
|
||||
'object' => 'Either a literal or a datasource uri that will be the object for this subjects new predicate.',
|
||||
'objecttype' => 'RDF object type, either "literal" for a literal (default), or "uri" for a datasource uri.');
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return array('Aqueduct RDF hard set API.');
|
||||
}
|
||||
|
||||
public function getVersion()
|
||||
{
|
||||
return __CLASS__ . '1.0i';
|
||||
}
|
||||
}
|
||||
131
includes/AqueductDbCalls.php
Normal file
131
includes/AqueductDbCalls.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
function aqDbChooseTable($whichtable)
|
||||
{
|
||||
global $wgAqueductTblname, $wgAqueductQueryTblname, $wgAqueductOldNSTblname;
|
||||
if ($whichtable == 'rdfsource')
|
||||
{
|
||||
return $wgAqueductTblname;
|
||||
}
|
||||
else if ($whichtable == 'query')
|
||||
{
|
||||
return $wgAqueductQueryTblname;
|
||||
}
|
||||
else if ($whichtable == 'oldns')
|
||||
{
|
||||
return $wgAqueductOldNSTblname;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Invalid table identifier');
|
||||
}
|
||||
}
|
||||
|
||||
// Simple function to get all rows from a table.
|
||||
// Takes a table name as an argument.
|
||||
// Returns an array of the rows.
|
||||
function aqDbTableGetAll ($whichtable = 'rdfsource')
|
||||
{
|
||||
$result = array();
|
||||
$db =& wfGetDB( DB_SLAVE );
|
||||
$res = $db->select(aqDbChooseTable($whichtable), '*');
|
||||
while($row = $db->fetchRow($res))
|
||||
{
|
||||
$result[] = $row;
|
||||
}
|
||||
$db->freeResult($res);
|
||||
|
||||
// XXX: Please note that the $db object gives a result that is DOUBLE the size of the row.
|
||||
// Storing each value under both its column name as a hash value AND under the column number.
|
||||
// This results in an array which is DOUBLE its true length, and if it is used in a loop
|
||||
// trying to iterate over the array, duplicates will appear. The following loop will
|
||||
// REMOVE the numbered duplicates and leave the associated array keyed by column name only.
|
||||
/*
|
||||
foreach ($result as $rows => $vals)
|
||||
{
|
||||
for ($i = 0; $i < count($vals) / 2; $i++)
|
||||
{
|
||||
unset($result[$rows][$i]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Simple function to insert a row into a table.
|
||||
// Takes the table to be modified and the column names and their values as an associated array.
|
||||
function aqDbInsertRow ($query, $whichtable = 'rdfsource')
|
||||
{
|
||||
$db =& wfGetDB( DB_WRITE );
|
||||
$db->insert(aqDbChooseTable($whichtable), $query);
|
||||
}
|
||||
|
||||
// Simple function to delete a row from a table.
|
||||
// Takes the table to be modified and the conditions and their values as an associated array.
|
||||
function aqDbDeleteRow ($cond, $whichtable = 'rdfsource')
|
||||
{
|
||||
$db =& wfGetDB( DB_WRITE );
|
||||
$db->delete(aqDbChooseTable($whichtable), $cond);
|
||||
}
|
||||
|
||||
// Simple function to replace a row from a table.
|
||||
// Takes the table to be modified,
|
||||
// the unique key of the row to replace,
|
||||
// and the row columns and values as an associated array.
|
||||
function aqDbReplaceRow ($unique, $row, $whichtable = 'rdfsource')
|
||||
{
|
||||
$db =& wfGetDB( DB_WRITE );
|
||||
$db->update(aqDbChooseTable($whichtable), $row, $unique);
|
||||
}
|
||||
|
||||
//Returns the commonly-used transtable, using an in-memory cache so it is not loaded from the database more than once
|
||||
function aqDbGetTransTable()
|
||||
{
|
||||
global $wgAqueductTransTable;
|
||||
if (!isset($wgAqueductTransTable))
|
||||
$wgAqueductTransTable = aqDbTableGetAll();
|
||||
return $wgAqueductTransTable;
|
||||
}
|
||||
|
||||
// Returns an array of the pages that exist in a NS.
|
||||
function aqNSHasPages ($ns)
|
||||
{
|
||||
$result = array();
|
||||
$db =& wfGetDB( DB_SLAVE );
|
||||
$res = $db->select('page', // from
|
||||
'page_title', // what
|
||||
array('page_namespace' => $ns)); // where
|
||||
|
||||
while($row = $db->fetchRow($res))
|
||||
{
|
||||
$result[] = $row['page_title'];
|
||||
}
|
||||
$db->freeResult($res);
|
||||
|
||||
return $result;
|
||||
}
|
||||
?>
|
||||
139
includes/AqueductEditPage.php
Normal file
139
includes/AqueductEditPage.php
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Modify the text coming into the edit page to allow help items for the Widget Tags to be displayed.
|
||||
function aqEditWidgetTagHelp($editpage)
|
||||
{
|
||||
global $wgAqueductWidgetTags, $wgAqueductAdvWidgetTags;
|
||||
aqProfile("aq");
|
||||
|
||||
// This call initates only the descriptions! We are in a hook that occurs before the wgParser is initialized.
|
||||
wfAqueductSetParserHooks(null);
|
||||
|
||||
$editpage->editFormPageTop .= '<br /><span style="font-size:larger;font-weight:bold">Available Aqueduct Widget Tags: </span><br />';
|
||||
$editpage->editFormPageTop .= 'Click the tag name to insert it into the page text at the cursor.<br />';
|
||||
// $editpage->editFormPageTop .= '<span style="font-weight:bold">Standard Widget Tags: </span><br />';
|
||||
// $editpage->editFormPageTop .= 'These tags do not require any parameters to be input.<br />';
|
||||
|
||||
foreach ($wgAqueductWidgetTags as $name => $description)
|
||||
{
|
||||
$editpage->editFormPageTop .= '<button type="button" name="'. $name .'" title="'. $description .'" class="tagInsert">' . $name . "</button>";
|
||||
}
|
||||
|
||||
$editpage->editFormPageTop .= '<br />';
|
||||
|
||||
if ($wgAqueductAdvWidgetTags)
|
||||
{
|
||||
$editpage->editFormPageTop .= '<br /><span style="font-weight:bold">Advanced Widget Tags: </span><br />';
|
||||
$editpage->editFormPageTop .= 'These tags require a parameter to be input as described for each tag below.<br />';
|
||||
|
||||
foreach ($wgAqueductAdvWidgetTags as $name => $description)
|
||||
{
|
||||
$editpage->editFormPageTop .= '<button type="button" name="'. $name .'" title="'. $description .'" class="tagInsertAdv">' . $name . '</button>';
|
||||
}
|
||||
|
||||
$editpage->editFormPageTop .= '<br /><br />';
|
||||
}
|
||||
|
||||
aqProfile("mw");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Function to insert the Javascript operations to insert the Tags when clicked.
|
||||
function aqEditWidgetTagJS($editpage)
|
||||
{
|
||||
global $wgOut, $wgScriptPath;
|
||||
$wgOut->addScriptFile($wgScriptPath.'/extensions/AqueductExtension/widget/js/jquery-1.3.2.min.js');
|
||||
|
||||
$wgOut->addScript(
|
||||
'<script type="text/javascript">
|
||||
function insertWidgetTag(text) {
|
||||
'.
|
||||
// Test for browser, because IE handles this in strange and silly fashions.
|
||||
'var txtarea = document.getElementById("wpTextbox1");
|
||||
var scrollPos = txtarea.scrollTop;
|
||||
var strPos = 0;
|
||||
var br = ((txtarea.selectionStart || txtarea.selectionStart == "0") ? "ff" : (document.selection ? "ie" : false ) );
|
||||
'.
|
||||
|
||||
// Give the element focus and extract the position.
|
||||
'if (br == "ie")
|
||||
{
|
||||
txtarea.focus();
|
||||
var range = document.selection.createRange();
|
||||
range.moveStart ("character", -txtarea.value.length);
|
||||
strPos = range.text.length;
|
||||
}
|
||||
else if (br == "ff")
|
||||
{
|
||||
strPos = txtarea.selectionStart;
|
||||
}
|
||||
'.
|
||||
|
||||
// Insert the tag.
|
||||
'var front = (txtarea.value).substring(0,strPos);
|
||||
var back = (txtarea.value).substring(strPos,txtarea.value.length);
|
||||
txtarea.value=front+text+back;
|
||||
strPos = strPos + text.length;
|
||||
'.
|
||||
|
||||
// Rework the selection to point JUST AFTER the tag that was just inserted.
|
||||
'if (br == "ie")
|
||||
{
|
||||
txtarea.focus();
|
||||
var range = document.selection.createRange();
|
||||
range.moveStart ("character", -txtarea.value.length);
|
||||
range.moveStart ("character", strPos);
|
||||
range.moveEnd ("character", 0);
|
||||
range.select();
|
||||
}
|
||||
else if (br == "ff")
|
||||
{
|
||||
txtarea.selectionStart = strPos;
|
||||
txtarea.selectionEnd = strPos;
|
||||
txtarea.focus();
|
||||
}
|
||||
txtarea.scrollTop = scrollPos;
|
||||
};
|
||||
|
||||
jQuery(document).ready(function() {
|
||||
jQuery(".tagInsert").click(function() {
|
||||
var name = jQuery(this).attr("name");
|
||||
var text = "\n<" + name + " />";
|
||||
insertWidgetTag(text);
|
||||
});
|
||||
jQuery(".tagInsertAdv").click(function() {
|
||||
var name = jQuery(this).attr("name");
|
||||
var text = "\n<" + name + "> INSERT YOUR PARAMETER HERE </" + name + ">";
|
||||
insertWidgetTag(text);
|
||||
});
|
||||
});
|
||||
</script>'
|
||||
);
|
||||
return true;
|
||||
}
|
||||
?>
|
||||
31
includes/AqueductExtension.i18n.php
Normal file
31
includes/AqueductExtension.i18n.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
$messages = array();
|
||||
|
||||
$messages['en'] = array(
|
||||
'aqueductconfiguration' => 'Aqueduct Configuration',
|
||||
);
|
||||
|
||||
328
includes/AqueductInterface.php
Normal file
328
includes/AqueductInterface.php
Normal file
@@ -0,0 +1,328 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
abstract class AqueductInterface
|
||||
{
|
||||
protected $mRow;
|
||||
|
||||
public function __construct($row)
|
||||
{
|
||||
$this->mRow = $row;
|
||||
}
|
||||
|
||||
public abstract function materialize($title);
|
||||
|
||||
public abstract function advancedOperation($title,$advancedrow);
|
||||
|
||||
//Sets one triple, doesn't disturb any triples with the same subject
|
||||
public abstract function hardSet($title, $predicateURI, $object, $objecttype);
|
||||
|
||||
public function titleToURI($title)
|
||||
{
|
||||
//1. Get the title text
|
||||
$t = $title->getDBkey();
|
||||
//Flip the title case if needed
|
||||
if ($this->mRow['aq_initial_lowercase'])
|
||||
{
|
||||
$t = strtolower(substr($t,0,1)) . substr($t,1);
|
||||
}
|
||||
|
||||
//2. If the URI begins with a backslash \, remove it. If the URI ends with a caret ^ , remove it.
|
||||
if ($t[0] == '\\')
|
||||
{
|
||||
$t = substr($t,1);
|
||||
}
|
||||
if ($t[strlen($t)-1] == '^')
|
||||
{
|
||||
$t = substr($t,0,strlen($t)-1);
|
||||
}
|
||||
//3. Process caret ^ escape sequences. A caret-period ^. is converted to a period. A caret-a ^a is converted to an ampersand & . A caret-underscore ^_ is converted to an underscore. A caret-tilde ^~ is converted to a tilde. Other such sequences are illegal.
|
||||
//4. Convert backticks ` to colons :
|
||||
//5. Convert backslashes \ to hash marks #
|
||||
$t = str_replace(array('^.','^a','^_','^~','`','\\'),array('.','&','_','~',':','#'),$t);
|
||||
if (strpos($t,'^') !== FALSE)
|
||||
{
|
||||
throw new Exception('Title has an illegal caret escape sequence');
|
||||
}
|
||||
|
||||
//6. Convert characters that are illegal in URIs to UTF-8 octet sequences (with the percent sign). Convert one character at a time. If a percent-dash octet sequence is encountered (as described above), keep it as a single-percent octet sequence.
|
||||
$legalcharpattern = '|[-[:alnum:];/?:@&=+$_.!~*(),\'#]|S';
|
||||
$result = '';
|
||||
$pos = 0;
|
||||
$length = strlen($t);
|
||||
while ($pos < $length)
|
||||
{
|
||||
if ($t[$pos] == '%')
|
||||
{
|
||||
//Percent dash encoded octet?
|
||||
if ($pos+4 > $length || $t[$pos+1] != '-')
|
||||
{
|
||||
throw new Exception('Unescaped title illegally has a percent-encoded octet sequence. This usually happens because the title was escaped multiple times.');
|
||||
}
|
||||
else
|
||||
{
|
||||
//Convert percent-dash encoded octet to a normally encoded octet.
|
||||
$result .= $t[$pos] . $t[$pos+2] . $t[$pos+3];
|
||||
}
|
||||
$pos += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (preg_match($legalcharpattern,$t[$pos])>0)
|
||||
{
|
||||
//Do not escape legal URI character.
|
||||
$result .= $t[$pos];
|
||||
}
|
||||
else
|
||||
{
|
||||
//Escape illegal URI character
|
||||
//The title object is already a UTF-8 encoded mbstring, so this will handle Unicode characters properly
|
||||
$result .= '%' . strtoupper(bin2hex($t[$pos]));
|
||||
}
|
||||
$pos ++;
|
||||
}
|
||||
}
|
||||
//Add URI prefix
|
||||
$result = $this->mRow['aq_source_uri'] . $result;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function uriToTitle($uri)
|
||||
{
|
||||
$transtable = aqDbGetTransTable();
|
||||
$legalchars = '[-[:alnum:];/?:@&=+$_.!~*(),\'#]';
|
||||
$legalcharpattern = '|' . $legalchars . '|S';
|
||||
$legalstringpattern = '|^' . $legalchars . '+$|SD';
|
||||
//1. Check for illegal characters
|
||||
if (preg_match($legalstringpattern,$uri)==0)
|
||||
{
|
||||
throw new Exception("Illegal URI: $uri");
|
||||
}
|
||||
//2. Detect which URI prefix is being used to select the configuration row, and remove the URI prefix
|
||||
$matchingrow = NULL;
|
||||
foreach ($transtable as $row)
|
||||
{
|
||||
//Use a configuration row if the URI prefix matches and another configuration row with a better (longer) prefix was not found
|
||||
if (strpos($uri,$row['aq_source_uri']) === 0)
|
||||
{
|
||||
if (!$matchingrow || strlen($matchingrow['aq_source_uri']) < strlen($row['aq_source_uri']))
|
||||
{
|
||||
$matchingrow = $row;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($matchingrow)
|
||||
{
|
||||
$uri = substr($uri,strlen($matchingrow['aq_source_uri']));
|
||||
}
|
||||
//3. Convert the sequences of octets into unicode characters.
|
||||
$decodeduri = '';
|
||||
$currentchar = 0;
|
||||
while ($currentchar < strlen($uri))
|
||||
{
|
||||
$c = $uri[$currentchar];
|
||||
if ($c == '%')
|
||||
{
|
||||
if ($currentchar + 3 > strlen($uri))
|
||||
{
|
||||
throw new Exception('Malformed escape sequence in URI: $uri');
|
||||
}
|
||||
$currentseqhex = $uri[$currentchar+1] . $uri[$currentchar+2];
|
||||
$currentseqdec = hexdec($currentseqhex);
|
||||
$currentseqbin = pack('H*', $currentseqhex);
|
||||
if ($currentseqdec < 128)
|
||||
{
|
||||
//This is a "non-encoded" character (code point <128)
|
||||
$encodeme = FALSE;
|
||||
if (preg_match($legalcharpattern,$currentseqbin)>0)
|
||||
{
|
||||
//URL-legal character was unnecessarily encoded. Output this in encoded form to preserve canonicalization
|
||||
$encodeme = TRUE;
|
||||
}
|
||||
else if ($currentseqdec < 32)
|
||||
{
|
||||
//Keep control characters encoded
|
||||
$encodeme = TRUE;
|
||||
}
|
||||
else if (strpos('<>[]|{}\`^% ',$currentseqbin) !== FALSE)
|
||||
{
|
||||
//Keep a character that we will not want to use in a wiki title encoded
|
||||
$encodeme = TRUE;
|
||||
}
|
||||
if ($encodeme)
|
||||
{
|
||||
$decodeduri = $decodeduri . '%-' . $currentseqhex;
|
||||
}
|
||||
else
|
||||
{
|
||||
$decodeduri = $decodeduri . $currentseqbin;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//This is part of a UTF-8 encoded sequence
|
||||
//Just output the byte to the wiki title, because we have nothing else to do with these characters
|
||||
$decodeduri = $decodeduri . $currentseqbin;
|
||||
}
|
||||
$currentchar+=3;
|
||||
}
|
||||
else
|
||||
{
|
||||
$decodeduri = $decodeduri . $c;
|
||||
$currentchar++;
|
||||
}
|
||||
}
|
||||
//4. The hash mark # could have been present in an unescaped form the URI, which would cause it to remain in the title at this point.
|
||||
//This character is illegal in the wiki. Convert it to a backslash \. If the hash mark was at the beginning of the title, convert it to a double backslash instead
|
||||
//5. Colons can be confused for namespace prefixes, so convert them to a backtick `
|
||||
$decodeduri = str_replace(array('#',':'),array('\\','`'),$decodeduri);
|
||||
if ($decodeduri[0] == '\\')
|
||||
{
|
||||
$decodeduri = '\\' . $decodeduri;
|
||||
}
|
||||
//6. Some characters will be conditionally escaped if they will cause problems.
|
||||
//Any period not adjacent with a character other than another period or the forward slash is escaped to ^
|
||||
//In a sequence of underscores, insert a ^ between all underscores, because Mediawiki will collapse sequences of underscores. Example: ___ turns into _caret_caret_ (caret means ^ )
|
||||
//Do the same in a sequence of tildes.
|
||||
$currentchar = 0;
|
||||
$printedunderscore = FALSE;
|
||||
$printedtilde = FALSE;
|
||||
$periodokay = FALSE;
|
||||
$escapeduri = '';
|
||||
for ($currentchar=0; $currentchar<strlen($decodeduri); $currentchar++)
|
||||
{
|
||||
$c = $decodeduri[$currentchar];
|
||||
if ($c == '_')
|
||||
{
|
||||
if ($printedunderscore)
|
||||
{
|
||||
$escapeduri .= '^';
|
||||
}
|
||||
$escapeduri .= '_';
|
||||
$printedunderscore = TRUE;
|
||||
$printedtilde = FALSE;
|
||||
$periodokay = TRUE;
|
||||
}
|
||||
else if ($c == '~')
|
||||
{
|
||||
if ($printedtilde)
|
||||
{
|
||||
$escapeduri .= '^';
|
||||
}
|
||||
$escapeduri .= '~';
|
||||
$printedunderscore = FALSE;
|
||||
$printedtilde = TRUE;
|
||||
$periodokay = TRUE;
|
||||
}
|
||||
else if ($c == '.')
|
||||
{
|
||||
if ($periodokay)
|
||||
{
|
||||
//The period is "armored" by the character on the left, so just print it
|
||||
$escapeduri .= '.';
|
||||
}
|
||||
else if ($currentchar+1<strlen($decodeduri))
|
||||
{
|
||||
$n = $decodeduri[$currentchar+1];
|
||||
if ($n!='.' && $n!='/')
|
||||
{
|
||||
//Period armored by the character on the right
|
||||
$escapeduri .= '.';
|
||||
}
|
||||
//Unarmored period
|
||||
$escapeduri .= '^.';
|
||||
}
|
||||
else
|
||||
{
|
||||
//Unarmored period at the end of the string
|
||||
$escapeduri .= '^.';
|
||||
}
|
||||
$printedunderscore = FALSE;
|
||||
$printedtilde = FALSE;
|
||||
$periodokay = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
$printedunderscore = FALSE;
|
||||
$printedtilde = FALSE;
|
||||
//Not an underscore or period or tilde, so we don't handle it in this loop.
|
||||
$escapeduri .= $c;
|
||||
if ($c != '/')
|
||||
{
|
||||
$periodokay = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
//If the URI contains any semicolons ;, escape all ampersands & to ^a
|
||||
if (strpos($escapeduri, ';') !== FALSE)
|
||||
{
|
||||
$escapeduri = str_replace('&','^a',$escapeduri);
|
||||
}
|
||||
//If the string ends with an underscore at this point, put a caret at the end so Mediawiki does not get rid of the underscore.
|
||||
if ($escapeduri[strlen($escapeduri)-1] == '_')
|
||||
{
|
||||
$escapeduri .= '^';
|
||||
}
|
||||
//7. Logic for characters that Mediawiki will modify only at the beginning of a string
|
||||
$prependbackslash = FALSE;
|
||||
if (strtoupper($escapeduri[0]) == $escapeduri[0])
|
||||
{
|
||||
if ($matchingrow && $matchingrow['aq_initial_lowercase'])
|
||||
{
|
||||
$prependbackslash = TRUE;
|
||||
}
|
||||
}
|
||||
else if (strtolower($escapeduri[0]) == $escapeduri[0])
|
||||
{
|
||||
if (!$matchingrow || !$matchingrow['aq_initial_lowercase'])
|
||||
{
|
||||
$prependbackslash = TRUE;
|
||||
}
|
||||
}
|
||||
else if ($escapeduri[0] == '_')
|
||||
{
|
||||
$prependbackslash = TRUE;
|
||||
}
|
||||
$escapeduri[0] = strtoupper($escapeduri[0]);
|
||||
if ($prependbackslash)
|
||||
{
|
||||
$escapeduri = '\\' . $escapeduri;
|
||||
}
|
||||
//8. Prepend the namespace
|
||||
if ($matchingrow)
|
||||
{
|
||||
if ($matchingrow['aq_wiki_namespace_id'] > 0)
|
||||
{
|
||||
$escapeduri = $matchingrow['aq_wiki_namespace'] . ':' . $escapeduri;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$escapeduri = 'Unknown:' . $escapeduri;
|
||||
}
|
||||
return $escapeduri;
|
||||
}
|
||||
}
|
||||
157
includes/AqueductInterfaceArc2.php
Normal file
157
includes/AqueductInterfaceArc2.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
class AqueductInterfaceArc2 extends AqueductInterface
|
||||
{
|
||||
protected function getEndpoint()
|
||||
{
|
||||
global $wgDBserver;
|
||||
global $wgDBname;
|
||||
global $wgDBuser;
|
||||
global $wgDBpassword;
|
||||
$config = array();
|
||||
$ep = null;
|
||||
if($this->mRow['aq_source_location'] == "")
|
||||
{
|
||||
$config = array(
|
||||
'db_host' => $wgDBserver,
|
||||
'db_name' => $wgDBname,
|
||||
'db_user' => $wgDBuser,
|
||||
'db_pwd' => $wgDBpassword,
|
||||
'store_name' => $this->mRow['aq_source_name']
|
||||
);
|
||||
$ep = ARC2::getStore($config);
|
||||
if (!$ep->isSetUp())
|
||||
{
|
||||
$ep->setUp(); /* create MySQL tables */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$config = array(
|
||||
'remote_store_endpoint' => $this->mRow['aq_source_location']
|
||||
);
|
||||
$ep = ARC2::getRemoteStore($config);
|
||||
}
|
||||
return $ep;
|
||||
|
||||
}
|
||||
|
||||
public function materialize($title)
|
||||
{
|
||||
$uri = $this->titleToURI($title);
|
||||
$ep = $this->getEndpoint();
|
||||
aqProfile("arc");
|
||||
$result = $ep->query('DESCRIBE <' . $uri . '>');
|
||||
aqProfile("aq");
|
||||
$triples = $result['result'];
|
||||
$result = array();
|
||||
$result[$title->getPrefixedDBkey()] = $triples;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function advancedOperation($title,$advancedrow)
|
||||
{
|
||||
$query = $advancedrow['aq_query'];
|
||||
$ep = $this->getEndpoint();
|
||||
|
||||
if ($title === NULL)
|
||||
{
|
||||
//No title because we are using an inline query.
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($query == '')
|
||||
{
|
||||
//Blank query, so use the page title as the query
|
||||
$query = $title->getText();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($advancedrow['aq_query_uri_param'])
|
||||
{
|
||||
//Insert the page's URI in the query where a double hash mark is seen.
|
||||
$replace = $this->titleToURI($title);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Insert the page name as a literal in the query where a double hash mark is seen
|
||||
//This is hard because the page name may contain characters that must be escaped
|
||||
//in a SPARQL literal.
|
||||
$replace = AqueductUtility::escapeSPARQLParameter($title->getText());
|
||||
//Now we have the literal that we will insert into the query.
|
||||
}
|
||||
$query = str_replace('##',$replace,$query);
|
||||
}
|
||||
}
|
||||
|
||||
aqProfile("arc");
|
||||
$result = $ep->query($query);
|
||||
aqProfile("aq");
|
||||
|
||||
if($result['query_type'] == 'select')
|
||||
{
|
||||
$ret = array();
|
||||
$currentresultid = 1;
|
||||
foreach ($result['result']['rows'] as $row)
|
||||
{
|
||||
$resultnode = array();
|
||||
foreach ($result['result']['variables'] as $var)
|
||||
{
|
||||
$resultnode[$var] []= array('value'=>$row[$var],'type'=>$row[$var . ' type']);
|
||||
}
|
||||
$ret['_SPARQL_'.$currentresultid] = array('urn:sparqlresult'.$currentresultid=>$resultnode);
|
||||
$currentresultid++;
|
||||
}
|
||||
}
|
||||
else if ($result['query_type'] == 'describe')
|
||||
{
|
||||
$index = $result['result'];
|
||||
$ret = array();
|
||||
foreach ($index as $key => $value)
|
||||
{
|
||||
$myvalues = array();
|
||||
$myvalues[$key] = $value;
|
||||
$ret[AqueductInterface::uriToTitle($key)] = $myvalues;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$index = $result['result'];
|
||||
$ret = array($title->getPrefixedDBkey() => $index);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function hardSet($title, $predicateURI, $object, $objecttype)
|
||||
{
|
||||
$uri = $this->titleToURI($title);
|
||||
$ep = $this->getEndpoint();
|
||||
|
||||
$ep -> insert(array(array('s'=>$uri,'p'=>$predicateURI,'o'=>$object,'o_type'=>$objecttype)),
|
||||
'urn:aqueduct:hardset');
|
||||
|
||||
}
|
||||
}
|
||||
303
includes/AqueductInterfaceBlackbook.php
Normal file
303
includes/AqueductInterfaceBlackbook.php
Normal file
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
abstract class AqueductInterfaceBlackbook extends AqueductInterface
|
||||
{
|
||||
//VERSION DEPENDENT FUNCTIONS
|
||||
protected abstract function getExecuteResults($algorithm, $datasource, $query, &$isModel);
|
||||
protected abstract function getMaterializeResults($uri);
|
||||
protected abstract function runPersistAlgorithm($rdfxml, $datasource);
|
||||
|
||||
//FUNCTIONS CALLED BY THE API
|
||||
public function hardSet($title, $predicateURI, $object, $objecttype)
|
||||
{
|
||||
// Materialize the RDF.
|
||||
$uri = $this->titleToURI($title);
|
||||
$reifiedindex = $this->getMaterializeResults($uri);
|
||||
$unreifiedindex = AqueductUtility::unReifyRDF($reifiedindex);
|
||||
|
||||
// Remove all data under this predicate and insert the new triple.
|
||||
$unreifiedindex[$uri][$predicateURI] = array(array('value' => $object, 'type' => $objecttype));
|
||||
|
||||
// Re-serialize the triples.
|
||||
aqProfile("arc");
|
||||
$parser = ARC2::getRDFXMLParser();
|
||||
$rdfxml = $parser->toRDFXML($unreifiedindex);
|
||||
aqProfile("aq");
|
||||
|
||||
// Collect the datasource name.
|
||||
$datasource = $this->mRow['aq_source_name'];
|
||||
|
||||
//print '<br>Datasource: '.$datasource.'<br>RDFXML: <br><br>'.$rdfxml;
|
||||
|
||||
// Persist the changes.
|
||||
// XXX: WARNING: This will only persist to ASSERTION datasources right now.
|
||||
// Fairly be ye warned.
|
||||
$this->runPersistAlgorithm($rdfxml, $datasource);
|
||||
}
|
||||
|
||||
public function materialize($title)
|
||||
{
|
||||
$result = $this->askWSCache($title);
|
||||
if ($result !== FALSE)
|
||||
return $result;
|
||||
|
||||
$uri = $this->titleToURI($title);
|
||||
$result = $this->materializeAndFormatUris(array($uri), $title);
|
||||
$this->setWSCache($title, $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function advancedOperation($title,$advancedrow)
|
||||
{
|
||||
//See if the is the operation supported by Blackbook (algorithm execution)
|
||||
if ($advancedrow['aq_query_type'] == 'ExecuteAlgorithm')
|
||||
{
|
||||
$datasource = $advancedrow['aq_datasource'];
|
||||
$query = $advancedrow['aq_query'];
|
||||
$algorithm = $advancedrow['aq_algorithm'];
|
||||
if ($title === NULL)
|
||||
{
|
||||
//No title because we are using an inline query.
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($query == '')
|
||||
{
|
||||
//Blank query, so use the page title as the query
|
||||
$query = $title->getText();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($advancedrow['aq_query_uri_param'])
|
||||
{
|
||||
//Insert the page's URI in the query where a double hash mark is seen.
|
||||
$replace = $this->titleToURI($title);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Insert the page name as a literal in the query where a double hash mark is seen
|
||||
//This is hard because the page name may contain characters that must be escaped
|
||||
//in a SPARQL literal.
|
||||
$replace = AqueductUtility::escapeSPARQLParameter($title->getText());
|
||||
}
|
||||
$query = str_replace('##',$replace,$query);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the cache
|
||||
$result = $this->askWSCache($datasource . $algorithm . $query);
|
||||
if ($result !== FALSE)
|
||||
return $result;
|
||||
|
||||
//Otherwise, Execute the algorithm normally
|
||||
$result = $this->getExecuteResults($algorithm,$datasource,$query,$isModel);
|
||||
|
||||
//Get or process the RDF from the algorithm execution
|
||||
if ($isModel)
|
||||
{
|
||||
aqProfile("arcBBRDFparse");
|
||||
aqProfile("aq");
|
||||
if ($algorithm == 'SparqlSelectQuery')
|
||||
{
|
||||
$outputindexarray = array();
|
||||
//Special handler for SPARQL select query
|
||||
//Check to see if we have RDF-style results or W3C-style results
|
||||
$xmldoc = DOMDocument::loadXML($result);
|
||||
$currentresultid = 1;
|
||||
if (strpos($xmldoc->documentElement->tagName,'sparql') !== FALSE)
|
||||
{
|
||||
//W3C XML SPARQL results
|
||||
$nodelist = $xmldoc->getElementsByTagName('result');
|
||||
foreach ($nodelist as $node)
|
||||
{
|
||||
$resultnode = array();
|
||||
$childlist = $node->childNodes;
|
||||
foreach ($childlist as $child)
|
||||
{
|
||||
if ($child->tagName=='binding')
|
||||
{
|
||||
$bindingname = $child->getAttribute('name');
|
||||
$bindingnodes = $child->childNodes;
|
||||
foreach ($bindingnodes as $bindingnode)
|
||||
{
|
||||
if (strpos($bindingnode->tagName,'uri') !== FALSE)
|
||||
{
|
||||
$resultnode[$bindingname] []= array('value'=>$bindingnode->textContent,'type'=>'uri');
|
||||
}
|
||||
else if (strpos($bindingnode->tagName,'literal') !== FALSE)
|
||||
{
|
||||
$resultnode[$bindingname] []= array('value'=>$bindingnode->textContent,'type'=>'literal');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$outputindexarray['_SPARQL_'.$currentresultid] = array('urn:sparqlresult'.$currentresultid=>$resultnode);
|
||||
|
||||
$currentresultid++;
|
||||
}
|
||||
}
|
||||
else if (strpos($xmldoc->documentElement->tagName,'rdf') !== FALSE)
|
||||
{
|
||||
//RDF-formatted SPARQL results
|
||||
//Keep track of the mapping between the Blackbook result identifiers and our generated IDs
|
||||
$resultids = array();
|
||||
//Look for reified RDF statements about the results
|
||||
$parser = ARC2::getRDFParser();
|
||||
$parser->parse('', $result);
|
||||
$index = $parser->getSimpleIndex(0);
|
||||
foreach ($index as $nodeid=>$nodecontents)
|
||||
{
|
||||
if (isset($nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject']))
|
||||
{
|
||||
//This is a reified RDF statement
|
||||
$s = $nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject'][0]['value'];
|
||||
if (!$nodeids[$s])
|
||||
{
|
||||
$nodeids[$s] = $currentresultid;
|
||||
$currentresultid++;
|
||||
$outputindexarray['_SPARQL_' . $nodeids[$s]] = array();
|
||||
}
|
||||
$outputindexarray['_SPARQL_' . $nodeids[$s]][$nodeid] = $nodecontents;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('SPARQL query result document type could not be detected.'.$xmldoc->documentElement->tagName);
|
||||
}
|
||||
|
||||
}
|
||||
else if ($algorithm == 'SparqlDescribeQuery')
|
||||
{
|
||||
$parser = ARC2::getRDFParser();
|
||||
$parser->parse('', $result);
|
||||
$index = $parser->getSimpleIndex(0);
|
||||
//Special handler for SPARQL describe query
|
||||
//This handler should also be used in any algorithm that returns a collection of clearly defined entities
|
||||
$outputindexarray = AqueductUtility::seperateReifiedRdfEntities($index);
|
||||
}
|
||||
else
|
||||
{
|
||||
$parser = ARC2::getRDFParser();
|
||||
$parser->parse('', $result);
|
||||
$index = $parser->getSimpleIndex(0);
|
||||
//Handler for SPARQL construct query, or any other query that cannot clearly be considered as
|
||||
//a collection of statements regarding clearly defined entities that reside in the dataset
|
||||
$outputindexarray[$title->getPrefixedDBkey()] = $index;
|
||||
}
|
||||
$this->setWSCache($datasource . $algorithm . $query, $outputindexarray);
|
||||
return $outputindexarray;
|
||||
}
|
||||
else
|
||||
{
|
||||
//We don't have RDF yet, just an array of URIs.
|
||||
//We must materialize.
|
||||
$materializeResult = $this->materializeAndFormatUris($result, NULL);
|
||||
|
||||
$this->setWSCache($datasource . $algorithm . $query, $materializeResult);
|
||||
return $materializeResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Unsupported advanced operation type');
|
||||
}
|
||||
}
|
||||
|
||||
protected function materializeAndFormatUris($uriarray, $defaulttitle)
|
||||
{
|
||||
//Materialize each URI in the array and return the whole collection as an array pointing to RDF-JSON structures keyed by wiki title.
|
||||
//This implementation will call materialize once for every URI, so the entities don't get mixed up. In the future, we may want to change this for speed.
|
||||
$result = array();
|
||||
foreach ($uriarray as $uri)
|
||||
{
|
||||
// Check the cache
|
||||
$triples = $this->askWSCache($uri);
|
||||
if ($triples === FALSE)
|
||||
{
|
||||
$triples = $this->getMaterializeResults($uri);
|
||||
$this->setWSCache($uri, $triples);
|
||||
}
|
||||
|
||||
if ($defaulttitle)
|
||||
{
|
||||
//There should be only one URI to materialize, and we know its wiki title already.
|
||||
$result[$defaulttitle->getPrefixedDBkey()] = $triples;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result[AqueductInterface::uriToTitle($uri)] = $triples;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function askWSCache($key)
|
||||
{
|
||||
global $aqMemcacheHost, $aqMemcachePort, $aqMemcacheExpirationTime;
|
||||
|
||||
// Check for existance of memcache and configuration
|
||||
if (!isset($aqMemcacheHost) || !function_exists(memcache_connect))
|
||||
return FALSE;
|
||||
|
||||
aqProfile("memcache");
|
||||
$result = FALSE;
|
||||
|
||||
// Connect to the server
|
||||
$connection = memcache_connect($aqMemcacheHost, $aqMemcachePort);
|
||||
|
||||
// Fail out to a query call if not connected.
|
||||
if ($connection === FALSE)
|
||||
return FALSE;
|
||||
|
||||
// Check to see if a value was hit.
|
||||
$result = memcache_get($connection, $key);
|
||||
aqProfile("aq");
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
protected function setWSCache($key, $result)
|
||||
{
|
||||
global $aqMemcacheHost, $aqMemcachePort, $aqMemcacheExpirationTime;
|
||||
|
||||
// Check for existance of memcache and configuration
|
||||
if (!isset($aqMemcacheHost) || !function_exists(memcache_connect))
|
||||
return FALSE;
|
||||
|
||||
aqProfile("memcache");
|
||||
// Connect to the server
|
||||
$connection = memcache_connect($aqMemcacheHost, $aqMemcachePort);
|
||||
|
||||
// Fail out if not connected.
|
||||
if ($connection === FALSE)
|
||||
return FALSE;
|
||||
|
||||
// Set the actual cache
|
||||
memcache_set($connection, $key, $result, MEMCACHE_COMPRESSED, $aqMemcacheExpirationTime);
|
||||
aqProfile("aq");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
152
includes/AqueductInterfaceBlackbook28.php
Normal file
152
includes/AqueductInterfaceBlackbook28.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
//Implementation of Blackbook interface that uses the Blackbook 2.8 web service interface
|
||||
class AqueductInterfaceBlackbook28 extends AqueductInterfaceBlackbook
|
||||
{
|
||||
protected function getExecuteResults($algorithm, $datasource, $query, &$isModel)
|
||||
{
|
||||
//Determine the algorithm class name and execution method
|
||||
switch ($algorithm)
|
||||
{
|
||||
case 'LuceneKeyword':
|
||||
$method = 'executeAlgorithmKeyword2URIProxy';
|
||||
$algorithmclass = 'blackbook.ejb.server.datamanager.LuceneKeyword';
|
||||
$isModel = FALSE;
|
||||
break;
|
||||
case 'SparqlConstructQuery':
|
||||
$method = 'executeAlgorithmKeyword2ModelProxy';
|
||||
$algorithmclass = 'blackbook.ejb.server.datamanager.SparqlConstructQueryAlgorithm';
|
||||
$isModel = TRUE;
|
||||
break;
|
||||
case 'SparqlDescribeQuery':
|
||||
$method = 'executeAlgorithmKeyword2ModelProxy';
|
||||
$algorithmclass = 'blackbook.ejb.server.datamanager.SparqlDescribeQueryAlgorithm';
|
||||
$isModel = TRUE;
|
||||
break;
|
||||
case 'SparqlSelectQuery':
|
||||
$method = 'executeAlgorithmKeyword2ModelProxy';
|
||||
$algorithmclass = 'blackbook.ejb.server.datamanager.SparqlSelectQueryAlgorithm';
|
||||
$isModel = TRUE;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown algorithm $algorithm. New algorithms can be defined in the AqueductInterfaceBlackbook class.");
|
||||
}
|
||||
return $this->doExecute($method, $algorithmclass, $datasource, $query);
|
||||
}
|
||||
|
||||
|
||||
private function doExecute($method, $algorithm, $datasource, $query)
|
||||
{
|
||||
//Implementation of execute that uses the PHP SOAP client
|
||||
if ($method == 'executeAlgorithmKeyword2ModelProxy')
|
||||
{
|
||||
$callparams = array('arg1' => $algorithm, 'arg2' => $datasource,'arg3' => $query);
|
||||
$rdf = $this->bbWebServiceCall('blackbookws/DataManager',$method,$callparams,true)->return;
|
||||
return $rdf;
|
||||
}
|
||||
else if ($method == 'executeAlgorithmKeyword2URIProxy')
|
||||
{
|
||||
$callparams = array('arg1' => $algorithm, 'arg2' => $datasource,'arg3' => $query);
|
||||
$uriarray = $this->bbWebServiceCall('blackbookws/DataManager',$method,$callparams,true)->return;
|
||||
if (!is_array($uriarray))
|
||||
{
|
||||
$uriarray = array($uriarray);
|
||||
if ($uriarray[0] == NULL)
|
||||
{
|
||||
$uriarray = array();
|
||||
}
|
||||
}
|
||||
return $uriarray;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Unknown algorithm execution method');
|
||||
}
|
||||
}
|
||||
|
||||
protected function getMaterializeResults($uri)
|
||||
{
|
||||
//Implementation of materialize that uses the PHP SOAP client
|
||||
$uriarray = array($uri);
|
||||
$materialize_parameters = array("arg1" => $uriarray, "arg2" => "No Assertions");
|
||||
$materialize_results = $this->bbWebServiceCall("blackbookws/DataManager", "materializeProxy", $materialize_parameters, true);
|
||||
$rdf=$materialize_results->return;
|
||||
aqProfile("arc");
|
||||
$parser = ARC2::getRDFXMLParser();
|
||||
$parser->parse('',$rdf);
|
||||
$triples = $parser->getSimpleIndex(0);
|
||||
aqProfile("aq");
|
||||
return $triples;
|
||||
}
|
||||
|
||||
// Call "persistProxy" or something of that sort using bbWebServiceCall with the given rdf into the given datasource.
|
||||
protected function runPersistAlgorithm($rdfxml, $datasource)
|
||||
{
|
||||
$callparams = array('arg1' => $datasource, 'arg2' => $rdfxml);
|
||||
$this->bbWebServiceCall('blackbookws/DataManager', 'persistProxy', $callparams, true);
|
||||
}
|
||||
|
||||
protected function getBrowserCertificate()
|
||||
{
|
||||
$cert = $_SERVER["SSL_CLIENT_CERT"];
|
||||
if (!$cert)
|
||||
{
|
||||
throw new Exception('You must call the API through https and send a valid client certificate. Either you did not pass a valid client certificate, or Apache is not set up to do proper certificate validation.');
|
||||
}
|
||||
else
|
||||
{
|
||||
return $cert;
|
||||
}
|
||||
}
|
||||
|
||||
private function bbWebServiceCall($managerName, $functionName, $params, $useProxy=false)
|
||||
{
|
||||
global $wgAqWsCache;
|
||||
if (!isset($wgAqWsCache))
|
||||
{
|
||||
$wgAqWsCache = array();
|
||||
}
|
||||
$blackbookURL = $this->mRow['aq_source_location'];
|
||||
$blackbookServerCertPath = $this->mRow['aq_source_cert_path'];
|
||||
$blackbookServerCertPassphrase = $this->mRow['aq_source_cert_pass'];
|
||||
$callparams = $params;
|
||||
if ($useProxy)
|
||||
{
|
||||
$callparams["arg0"] = $this->getBrowserCertificate();
|
||||
}
|
||||
$wsdlpath = $blackbookURL . $managerName . "?wsdl";
|
||||
if (!isset($wgAqWsCache[$wsdlpath]))
|
||||
{
|
||||
aqProfile("wsclient");
|
||||
$wgAqWsCache[$wsdlpath] = new SOAPClient($wsdlpath,
|
||||
array("local_cert" => $blackbookServerCertPath, "passphrase" => $blackbookServerCertPassphrase, "exceptions" => true));
|
||||
}
|
||||
|
||||
aqProfile("wscall");
|
||||
$results = call_user_func(array($wgAqWsCache[$wsdlpath], $functionName), $callparams);
|
||||
aqProfile("aq");
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
192
includes/AqueductInterfaceBlackbook30.php
Normal file
192
includes/AqueductInterfaceBlackbook30.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
//Implementation of Blackbook interface that uses the Blackbook 3.0 web service interface
|
||||
class AqueductInterfaceBlackbook30 extends AqueductInterfaceBlackbook
|
||||
{
|
||||
protected function getExecuteResults($algorithm, $datasource, $query, &$isModel)
|
||||
{
|
||||
//Determine the algorithm class name and execution method
|
||||
switch ($algorithm)
|
||||
{
|
||||
case 'LuceneKeyword':
|
||||
$method = 'executeKeyword';
|
||||
$algorithmclass = 'blackbook.ejb.server.algorithm';
|
||||
$isModel = FALSE;
|
||||
break;
|
||||
case 'SparqlConstructQuery':
|
||||
$method = 'executeSPARQL';
|
||||
$algorithmclass = 'blackbook.ejb.server.sparql';
|
||||
$isModel = TRUE;
|
||||
break;
|
||||
case 'SparqlDescribeQuery':
|
||||
$method = 'executeSPARQL';
|
||||
$algorithmclass = 'blackbook.ejb.server.sparql';
|
||||
$isModel = TRUE;
|
||||
break;
|
||||
case 'SparqlSelectQuery':
|
||||
$method = 'executeSPARQL';
|
||||
$algorithmclass = 'blackbook.ejb.server.sparql';
|
||||
$isModel = TRUE;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown algorithm $algorithm. New algorithms can be defined in the AqueductInterfaceBlackbook class.");
|
||||
}
|
||||
return $this->doExecute($method, $algorithmclass, $datasource, $query);
|
||||
}
|
||||
|
||||
|
||||
private function doExecute($method, $algorithm, $datasource, $query)
|
||||
{
|
||||
//Implementation of execute that uses the PHP SOAP client
|
||||
if ($method == 'executeKeyword')
|
||||
{
|
||||
$callparams = array('queryRequest' => array('sourceDataSource' => $datasource,'query' => $query));
|
||||
$keywordresults = $this->bbWebServiceCall('blackbookws/AlgorithmManagerProxy',$method,$callparams, true)->return;
|
||||
$uris = $keywordresults->uris;
|
||||
if (!is_array($uris))
|
||||
{
|
||||
$uris = array($uris);
|
||||
}
|
||||
//error_log($uris);
|
||||
return $uris;
|
||||
}
|
||||
else if($method == 'executeSPARQL')
|
||||
{
|
||||
// TODO: annotations are missing in Blackbook3.0 RC 9 that must be fixed for this to work
|
||||
$callparams = array('query' => $query);
|
||||
$rdf = $this->bbWebServiceCall('blackbookws/SparqlQueryManagerProxy', 'query', $callparams, true)->return;
|
||||
return $rdf;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Unknown algorithm execution method');
|
||||
}
|
||||
}
|
||||
|
||||
protected function getMaterializeResults($uri)
|
||||
{
|
||||
$rdf = $this->getMaterializeResultsRDF($uri);
|
||||
aqProfile("arc");
|
||||
$parser = ARC2::getRDFXMLParser();
|
||||
$parser->parse('',$rdf);
|
||||
$triples = $parser->getSimpleIndex(0);
|
||||
aqProfile("aq");
|
||||
//Get rid of the "materialized=true" that Blackbook returns when materializing
|
||||
$forunset = NULL;
|
||||
foreach ($triples as $subj=>$subjcontents)
|
||||
{
|
||||
if (isset($subjcontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate']) &&
|
||||
$subjcontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate'][0]['value'] == 'urn:blackbook:materialized')
|
||||
$forunset = $subj;
|
||||
}
|
||||
if ($forunset !== NULL)
|
||||
{
|
||||
unset($triples[$forunset]);
|
||||
}
|
||||
return $triples;
|
||||
}
|
||||
|
||||
private function getMaterializeResultsRDF($uri)
|
||||
{
|
||||
//Implementation of materialize that uses the PHP SOAP client
|
||||
$uriarray = array($uri);
|
||||
$materialize_parameters = array("uriSetRequest" => array("uris" => $uriarray));
|
||||
$materialize_results = $this->bbWebServiceCall("blackbookws/AlgorithmManagerProxy", "executeMaterialize", $materialize_parameters, true);
|
||||
$temp_datasource = $materialize_results->return->dataSource;
|
||||
$rdf=$this->retrieveResults($temp_datasource);
|
||||
//error_log($rdf);
|
||||
return $rdf;
|
||||
}
|
||||
|
||||
protected function retrieveResults($tempDS)
|
||||
{
|
||||
$data = array("dataSource" => $tempDS);
|
||||
$algorithm_parameters = new SoapVar($data, SOAP_ENC_OBJECT, 'rdfRetrievalRequest');
|
||||
$jena_parameters = array("algorithm" => "Jena Retrieve", "algorithmRequest" => $algorithm_parameters);
|
||||
$retrieve_results = $this->bbWebServiceCall("blackbookws/AlgorithmManagerProxy", "execute", $jena_parameters, true);
|
||||
//Now we can delete the temp datasource because it will no longer be needed
|
||||
$this->bbWebServiceCall('blackbookws/MetadataManagerProxy', 'removeTemporaryDS', array('name'=>$tempDS), true);
|
||||
//BUG: Must delete it twice for it to actually delete
|
||||
$this->bbWebServiceCall('blackbookws/MetadataManagerProxy', 'removeTemporaryDS', array('name'=>$tempDS), true);
|
||||
return $retrieve_results;
|
||||
}
|
||||
|
||||
// Call "persistProxy" or something of that sort using bbWebServiceCall with the given rdf into the given datasource.
|
||||
protected function runPersistAlgorithm($rdfxml, $datasource)
|
||||
{
|
||||
$persist_params = array('rdfRequest' => array("destinationDataSource" => $datasource, "rdf" => $rdfxml));
|
||||
$this->bbWebServiceCall('blackbookws/AlgorithmManagerProxy', 'executePersist', $persist_params, true);
|
||||
}
|
||||
|
||||
//Function to be called from maintenance scripts
|
||||
public function deleteAllTemporaryDatasources()
|
||||
{
|
||||
$this->bbWebServiceCall('blackbookws/MetadataManagerProxy', 'removeAllTemporaryDS', array(), true);
|
||||
}
|
||||
|
||||
protected function getBrowserCertificate()
|
||||
{
|
||||
$cert = $_SERVER["SSL_CLIENT_CERT"];
|
||||
if (!$cert)
|
||||
{
|
||||
throw new Exception('You must call the API through https and send a valid client certificate. Either you did not pass a valid client certificate, or Apache is not set up to do proper certificate validation.');
|
||||
}
|
||||
else
|
||||
{
|
||||
return $cert;
|
||||
}
|
||||
}
|
||||
|
||||
private function bbWebServiceCall($managerName, $functionName, $params, $useProxy=false)
|
||||
{
|
||||
$blackbookURL = $this->mRow['aq_source_location'];
|
||||
$blackbookServerCertPath = $this->mRow['aq_source_cert_path'];
|
||||
$blackbookServerCertPassphrase = $this->mRow['aq_source_cert_pass'];
|
||||
$callparams = $params;
|
||||
if ($useProxy)
|
||||
{
|
||||
$callparams["publicKey"] = $this->getBrowserCertificate();
|
||||
}
|
||||
|
||||
aqProfile("wsclient");
|
||||
$blackbookWSClient = new SOAPClient($blackbookURL . $managerName . "?wsdl",
|
||||
array('local_cert' => $blackbookServerCertPath, 'passphrase' => $blackbookServerCertPassphrase,'trace' => ($functionName == 'execute')));
|
||||
aqProfile("wscall");
|
||||
$results = call_user_func(array($blackbookWSClient, $functionName) ,$callparams);
|
||||
aqProfile("aq");
|
||||
|
||||
//error_log(print_r($results,true));
|
||||
if($functionName == 'execute')
|
||||
{
|
||||
$response = $blackbookWSClient->__getLastResponse();
|
||||
$xmldoc = DOMDocument::loadXML($response);
|
||||
$rdfnodes = $xmldoc->getElementsByTagName('rdf');
|
||||
if ($rdfnodes->length>0)
|
||||
{
|
||||
$results = $rdfnodes->item(0)->textContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('RDF not found in Blackbook results retrieval');
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
169
includes/AqueductInterfaceEmbedded.php
Normal file
169
includes/AqueductInterfaceEmbedded.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class AqueductInterfaceEmbedded extends AqueductInterface
|
||||
{
|
||||
public function materialize($title)
|
||||
{
|
||||
$forest = $this->extractTriplesFromPage($title, NULL);
|
||||
if ($this->mRow['aq_search_fragments'])
|
||||
{
|
||||
$s = $title->getPrefixedText();
|
||||
$l = strpos($s, '\\');
|
||||
if ($l !== FALSE)
|
||||
{
|
||||
//Strip the fragment and make newtitle
|
||||
if ($l==0)
|
||||
{
|
||||
throw new Exception('Unexpected hash mark appeared in query URI');
|
||||
}
|
||||
$newtitle = Title::newFromText(substr($s,0,$l));
|
||||
$tree = $this->extractTriplesFromPage($newtitle,$title);
|
||||
if (isset($forest[$s]))
|
||||
{
|
||||
//Triples for the title were found both on the "base" and the "fragmented" page, so merge them
|
||||
$forest[$s] = ARC2::getMergedIndex($tree,$forest[$s]);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Only found triples on the "base" page
|
||||
$forest[$s] = $tree;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $forest;
|
||||
}
|
||||
|
||||
//If desiredtitle is NULL, return a key-value set of RDF-JSON structures, keyed by the title plus the found fragments
|
||||
//If desiredtitle is NOT NULL, just return an RDF-JSON structure representing all triples that match desiredtitle after appending the found fragment
|
||||
//The first and second param must be a Title object
|
||||
protected function extractTriplesFromPage($title,$desiredtitle)
|
||||
{
|
||||
global $wgAqueductTriplesAdded;
|
||||
$result = array();
|
||||
$wgAqueductTriplesAdded = array();
|
||||
//1. Parse the page that we are looking on and collect triples
|
||||
$p = new Parser();
|
||||
wfAqueductSetParserHooks($p);
|
||||
$p->disableCache();
|
||||
$po = new ParserOptions();
|
||||
$a = new Article($title);
|
||||
$p->parse($a->getRawText(),$title,$po);
|
||||
$triples = $wgAqueductTriplesAdded;
|
||||
unset($GLOBALS['wgAqueductTriplesAdded']);
|
||||
//2. Do title->uri conversion on the current page
|
||||
$uri = $this->titleToURI($title);
|
||||
$titletext = $title->getPrefixedDBkey();
|
||||
$desireduri = NULL;
|
||||
if ($desiredtitle !== NULL)
|
||||
{
|
||||
$desireduri = $this->titleToURI($desiredtitle);
|
||||
}
|
||||
//4. Construct an ARC2 index by appending the fragments to the base URIs for subject, use the literal predicates, and the uri or literal objects if they exist
|
||||
$tripleindex = array();
|
||||
$tripletitlecache = array();
|
||||
foreach ($triples as $triple)
|
||||
{
|
||||
//Determine the URI subject of the triple
|
||||
$triplesubject = $uri;
|
||||
if ($triple['fragment'] !== NULL)
|
||||
{
|
||||
$triplesubject = $triplesubject . '#' . $triple['fragment'];
|
||||
}
|
||||
//Determine if the triple will be thrown out (for having the wrong subject)
|
||||
if ($desireduri===NULL || $desireduri == $triplesubject)
|
||||
{
|
||||
//Do not throw out this triple
|
||||
if ($desireduri == NULL)
|
||||
{
|
||||
//We could return multiple named RDF graphs here. Figure out which graph to return
|
||||
if ($triple['fragment'] !== NULL)
|
||||
{
|
||||
if (isset($tripletitlecache[$triplesubject]))
|
||||
{
|
||||
$graphname = $tripletitlecache[$triplesubject];
|
||||
}
|
||||
else
|
||||
{
|
||||
$graphname = AqueductInterface::uriToTitle($triplesubject);
|
||||
$tripletitlecache[$triplesubject] = $graphname;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$graphname = $titletext;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Not returning multiple named graphs
|
||||
$graphname = NULL;
|
||||
}
|
||||
//Now we know the URI subject of the RDF triple, and the name of the RDF graph we will add it to
|
||||
$uripredicate = $triple['predicate'];
|
||||
//Determine the object of the RDF triple
|
||||
if ($triple['objecttype'] === NULL || $triple['objecttype'] == 'literal')
|
||||
{
|
||||
$object = $triple['object'];
|
||||
$objecttype = 'literal';
|
||||
}
|
||||
else if ($triple['objecttype'] == 'page')
|
||||
{
|
||||
$object = AqueductUtility::titleToURIStatic($triple['object']);
|
||||
$objecttype = 'uri';
|
||||
}
|
||||
else if ($triple['objecttype'] == 'uri')
|
||||
{
|
||||
$object = $triple['object'];
|
||||
$objecttype = 'uri';
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Bad object type in embedded triple');
|
||||
}
|
||||
//Add the RDF triple to the graph
|
||||
if ($graphname !== NULL)
|
||||
{
|
||||
$result[$graphname][$triplesubject][$uripredicate][] = array('value' => $object, 'type' => $objecttype);
|
||||
}
|
||||
else
|
||||
{
|
||||
$result[$triplesubject][$uripredicate][] = array('value' => $object, 'type' => $objecttype);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function advancedOperation($title,$advancedrow)
|
||||
{
|
||||
throw new Exception('Advanced operations are not supported for the embedded datasource.');
|
||||
}
|
||||
|
||||
public function hardSet($title, $predicateURI, $object, $objecttype)
|
||||
{
|
||||
throw new Exception('Cannot persist to the embedded datasource.');
|
||||
}
|
||||
}
|
||||
65
includes/AqueductInterfaceMemcached.php
Normal file
65
includes/AqueductInterfaceMemcached.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class AqueductInterfaceMemcached extends AqueductInterfaceBlackbook
|
||||
{
|
||||
//Like the Blackbook interface, but data is coming from memcached (loaded externally) instead of coming from Blackbook.
|
||||
protected function getMaterializeResults($uri)
|
||||
{
|
||||
global $aqMemcacheHost, $aqMemcachePort;
|
||||
|
||||
// Check for existance of memcache and configuration
|
||||
if (!function_exists(memcache_connect) || !isset($aqMemcacheHost))
|
||||
throw new Exception('memcached PHP functions not found, or aqMemcacheHost not set.');
|
||||
|
||||
aqProfile("memcache");
|
||||
|
||||
// Connect to the server
|
||||
$connection = memcache_connect($aqMemcacheHost, $aqMemcachePort);
|
||||
if ($connection === FALSE)
|
||||
throw new Exception('The connection to the memcached server failed.');
|
||||
|
||||
// Check to see if a value was hit.
|
||||
$result = memcache_get($connection, $uri);
|
||||
|
||||
aqProfile("arc");
|
||||
$parser = ARC2::getRDFParser();
|
||||
$parser->parse('',$result);
|
||||
$triples = $parser->getSimpleIndex(0);
|
||||
aqProfile("aq");
|
||||
|
||||
return $triples;
|
||||
}
|
||||
|
||||
protected function getExecuteResults($algorithm, $datasource, $query, &$isModel)
|
||||
{
|
||||
throw new Exception('Advanced operations are not supported for the memcached datasource.');
|
||||
}
|
||||
|
||||
protected function runPersistAlgorithm($rdfxml, $datasource)
|
||||
{
|
||||
throw new Exception('Cannot persist to the memcached datasource.');
|
||||
}
|
||||
}
|
||||
82
includes/AqueductInterfaceTest.php
Normal file
82
includes/AqueductInterfaceTest.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class AqueductInterfaceTest extends AqueductInterfaceBlackbook
|
||||
{
|
||||
//Like the Blackbook interface, but data is static instead of coming from Blackbook.
|
||||
protected function getMaterializeResults($uri)
|
||||
{
|
||||
if ($uri == 'uri:citydata:Chicago')
|
||||
{
|
||||
$ntriples = '
|
||||
<uri:citydata:Chicago> <uri:cityschema:HasNeighbor> <uri:citydata:Gary> .
|
||||
<uri:citydata:Chicago> <uri:cityschema:HasNeighbor> <uri:citydata:Skokie> .
|
||||
<uri:citydata:Chicago> <uri:cityschema:Population> "2853114" .
|
||||
<uri:citydata:Chicago> <uri:cityschema:State> "IL" .
|
||||
<uri:citydata:Chicago> <uri:cityschema:PovertyRate> "19.6" .
|
||||
';
|
||||
}
|
||||
else if ($uri == 'uri:citydata:Gary')
|
||||
{
|
||||
$ntriples = '
|
||||
<uri:citydata:Gary> <uri:cityschema:HasNeighbor> <uri:citydata:Chicago> .
|
||||
<uri:citydata:Gary> <uri:cityschema:Population> "99516" .
|
||||
<uri:citydata:Gary> <uri:cityschema:State> "IN" .
|
||||
<uri:citydata:Gary> <uri:cityschema:PovertyRate> "25.8" .
|
||||
';
|
||||
}
|
||||
else if ($uri == 'uri:citydata:Skokie')
|
||||
{
|
||||
$ntriples = '
|
||||
<uri:citydata:Skokie> <uri:cityschema:HasNeighbor> <uri:citydata:Chicago> .
|
||||
<uri:citydata:Skokie> <uri:cityschema:Population> "66559" .
|
||||
<uri:citydata:Skokie> <uri:cityschema:State> "IL" .
|
||||
<uri:citydata:Skokie> <uri:cityschema:PovertyRate> "5.4" .
|
||||
';
|
||||
}
|
||||
else
|
||||
{
|
||||
$ntriples = '';
|
||||
}
|
||||
|
||||
aqProfile("arc");
|
||||
$parser = ARC2::getRDFParser();
|
||||
$parser->parse('',$ntriples);
|
||||
$triples = $parser->getSimpleIndex(0);
|
||||
aqProfile("aq");
|
||||
|
||||
return $triples;
|
||||
}
|
||||
|
||||
protected function getExecuteResults($algorithm, $datasource, $query, &$isModel)
|
||||
{
|
||||
throw new Exception('Advanced operations are not supported for the test datasource.');
|
||||
}
|
||||
|
||||
protected function runPersistAlgorithm($rdfxml, $datasource)
|
||||
{
|
||||
throw new Exception('Cannot persist to the test datasource.');
|
||||
}
|
||||
}
|
||||
143
includes/AqueductPagePopulation.php
Normal file
143
includes/AqueductPagePopulation.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
// Include the aqDB calls to get to the aqTransTable, and the interfaces for materialization.
|
||||
require_once('extensions/AqueductExtension/includes/AqueductDbCalls.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterface.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceBlackbook.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceTest.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceBlackbook28.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceBlackbook30.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceEmbedded.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceMemcached.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductInterfaceArc2.php');
|
||||
require_once('extensions/AqueductExtension/includes/AqueductUtility.php');
|
||||
require_once('extensions/AqueductExtension/arc/ARC2.php');
|
||||
|
||||
// Prepopulates a page when you follow a red link to it. Currently only fires when a red link is used.
|
||||
function aqPopulateNewPage($editpage)
|
||||
{
|
||||
global $wgOut, $wgRequest;
|
||||
aqProfile("aq");
|
||||
|
||||
// Check if this is a page created by following a red link to a non-existant page.
|
||||
if (!$editpage->mTitle->exists())
|
||||
{
|
||||
// Grab the title for the page we're going to populate
|
||||
$newArticle = $editpage->getArticle();
|
||||
$newTitle = $newArticle->getTitle();
|
||||
|
||||
$basicrow = NULL;
|
||||
$advancedrow = NULL;
|
||||
AqueductUtility::getRowsForAqueductTitle($newTitle, $basicrow, $advancedrow);
|
||||
|
||||
// Actually do the ignoring.
|
||||
if ($basicrow === NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Decide what article to use as a template for the new page.
|
||||
if ($advancedrow !== NULL)
|
||||
{
|
||||
$insertTitle = Title::newFromText('Template:' . $advancedrow['aq_wiki_parent_namespace'] . '_' . $advancedrow['aq_wiki_namespace_tag']);
|
||||
if (!$insertTitle || !$insertTitle->exists())
|
||||
{
|
||||
$insertTitle = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$insertTitle = Title::newFromText('Template:' . $basicrow['aq_wiki_namespace']);
|
||||
if (!$insertTitle || !$insertTitle->exists())
|
||||
{
|
||||
$insertTitle = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($insertTitle)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Materialize the entity to check the RDF type, we may be able to use a more specific template.
|
||||
if ($advancedrow === NULL)
|
||||
{
|
||||
$interface = AqueductUtility::getInterfaceForRow($basicrow);
|
||||
|
||||
// This $result contains the RDF from which we need to collect the RDF type to compare against templates.
|
||||
$result = $interface->materialize($newTitle);
|
||||
|
||||
foreach ($result as $r => $record)
|
||||
{
|
||||
foreach ($record as $s => $subj)
|
||||
{
|
||||
if (AqueductInterface::uriToTitle($s) == $newTitle)
|
||||
{
|
||||
if ($result[$r][$s]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'])
|
||||
{
|
||||
$newInsertTitle = $result[$r][$s]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'][0]['value'];
|
||||
$newInsertTitle = AqueductInterface::uriToTitle($newInsertTitle);
|
||||
$newInsertTitle = Title::newFromText('Template:' . $newInsertTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
unset($newInsertTitle);
|
||||
}
|
||||
|
||||
if ($newInsertTitle && $newInsertTitle->exists())
|
||||
{
|
||||
$insertTitle = $newInsertTitle;
|
||||
}
|
||||
|
||||
// Collect the article to use as a template for the new page.
|
||||
$insertArticle = new Article($insertTitle);
|
||||
|
||||
// Get the template used to populate this page and write it to the new page.
|
||||
$newArticle->doEdit($insertArticle->getRawText(), "Page Pre-populated using the Aqueduct Page Population Extension.");
|
||||
|
||||
// Redirect to the new page so the user doesn't even know it didn't exist.
|
||||
$wgOut->redirect($newTitle->getFullURL());
|
||||
|
||||
// Make sure the user doesn't ever see the edit window.
|
||||
aqProfile("mw");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
aqProfile("mw");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Any other edits should continue normally.
|
||||
aqProfile("mw");
|
||||
return true;
|
||||
}
|
||||
?>
|
||||
336
includes/AqueductUtility.php
Normal file
336
includes/AqueductUtility.php
Normal file
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
abstract class AqueductUtility
|
||||
{
|
||||
//STATIC UTILITY FUNCTIONS
|
||||
|
||||
//Take a wiki title as input, and see if it is associated with Aqueduct namespaces (as defined on the special page.)
|
||||
//If it is associated with a basic namespace, return the row in the basicrow parameter
|
||||
//If it is associated with an advanced namespace, return the rows in the basicrow and advancedrow parameters
|
||||
public static function getRowsForAqueductTitle($title, &$basicrow, &$advancedrow)
|
||||
{
|
||||
$transtable = aqDbGetTransTable();
|
||||
$basicrow = NULL;
|
||||
$advancedrow = NULL;
|
||||
$ns = $title->getNamespace();
|
||||
//See if this is a basic query
|
||||
foreach ($transtable as $row)
|
||||
{
|
||||
if ($row['aq_wiki_namespace_id'] == $ns)
|
||||
{
|
||||
$basicrow = $row;
|
||||
return;
|
||||
}
|
||||
}
|
||||
//See if this was an advanced query
|
||||
$querytable = aqDbTableGetAll('query');
|
||||
foreach ($querytable as $advrow)
|
||||
{
|
||||
if ($advrow['aq_wiki_namespace_id'] == $ns)
|
||||
{
|
||||
$advancedrow = $advrow;
|
||||
$basicrow = AqueductUtility::getBasicRowFromAdvancedRow($advrow);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//Look up the basic row that is "chained" to the given advanced row
|
||||
public static function getBasicRowFromAdvancedRow($advancedrow)
|
||||
{
|
||||
$transtable = aqDbGetTransTable();
|
||||
foreach ($transtable as $brow)
|
||||
{
|
||||
if ($brow['aq_wiki_namespace'] == $advancedrow['aq_wiki_parent_namespace'])
|
||||
{
|
||||
return $brow;
|
||||
}
|
||||
}
|
||||
if (!$foundrow)
|
||||
{
|
||||
throw new Exception('The parent namespace for an advanced query was not found.');
|
||||
}
|
||||
}
|
||||
|
||||
//Return an instance of AqueductInterface that can be used to do queries for the given row
|
||||
public static function getInterfaceForRow($basicrow)
|
||||
{
|
||||
switch ($basicrow['aq_source_type'])
|
||||
{
|
||||
case 'BB':
|
||||
$interface = new AqueductInterfaceBlackbook28($basicrow);
|
||||
break;
|
||||
case 'Embedded':
|
||||
$interface = new AqueductInterfaceEmbedded($basicrow);
|
||||
break;
|
||||
case 'BB28':
|
||||
$interface = new AqueductInterfaceBlackbook28($basicrow);
|
||||
break;
|
||||
case 'BB30':
|
||||
$interface = new AqueductInterfaceBlackbook30($basicrow);
|
||||
break;
|
||||
case 'Test':
|
||||
$interface = new AqueductInterfaceTest($basicrow);
|
||||
break;
|
||||
case 'Memcached':
|
||||
$interface = new AqueductInterfaceMemcached($basicrow);
|
||||
break;
|
||||
case 'Arc2':
|
||||
$interface = new AqueductInterfaceArc2($basicrow);
|
||||
break;
|
||||
default:
|
||||
throw new Exception('The datasource type for this namespace is invalid or unsupported.');
|
||||
}
|
||||
return $interface;
|
||||
}
|
||||
|
||||
//Convenience function that finds the Aqueduct configuration row associated with a title
|
||||
//for the sole purpose of converting the title to a URI.
|
||||
//To avoid wasted effort, this function should not be called if any interface functions will
|
||||
//ever be called on the title.
|
||||
//This convenience function takes the title as a string (unlike the other ones) and it can
|
||||
//throw an exception if the namespace is not under Aqueduct's control.
|
||||
public static function titleToURIStatic($titlestring)
|
||||
{
|
||||
$t = Title::newFromText($titlestring);
|
||||
$basicrow = NULL;
|
||||
$advancedrow = NULL;
|
||||
AqueductUtility::getRowsForAqueductTitle($t,$basicrow,$advancedrow);
|
||||
return AqueductUtility::getInterfaceForRow($basicrow)->titleToURI($t);
|
||||
}
|
||||
|
||||
//Return an array where reified RDF statements are seperated by subject, and all statements for a particular subject
|
||||
//are put under the appropriate key of the returned array.
|
||||
//This is non-trivial because complex structures involving bnodes make the subject that a bnode is ultimately associated
|
||||
//with non-obvious.
|
||||
//Input: An ARC2 SimpleIndex structure
|
||||
//Output: An array where the keys are the subject URIs and the values are arrays of reified RDF statements
|
||||
//(each statement being represented as an ARC2 SimpleIndex)
|
||||
public static function seperateReifiedRdfEntities($index)
|
||||
{
|
||||
$bnodeMappings = array();
|
||||
$output = array();
|
||||
//Look for reified RDF statements about the results
|
||||
foreach ($index as $nodeid=>$nodecontents)
|
||||
{
|
||||
if (isset($nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject']))
|
||||
{
|
||||
//This is a reified RDF statement
|
||||
$s = $nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject'][0]['value'];
|
||||
$t = $nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject'][0]['type'];
|
||||
$o = $nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#object'][0]['value'];
|
||||
$ot = $nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#object'][0]['type'];
|
||||
//See if we know what the bnode is connected to
|
||||
if ($t == 'bnode' && isset($bnodeMappings[$s]))
|
||||
{
|
||||
$s = $bnodeMappings[$s];
|
||||
}
|
||||
//Put the node under the proper key of the output array
|
||||
if (!isset($output[$s]))
|
||||
{
|
||||
$output[$s] = array();
|
||||
}
|
||||
$output[$s][$nodeid] = $nodecontents;
|
||||
//See if this statement will allow us to disambiguate the ultimate subject of another statement
|
||||
if ($ot == 'bnode')
|
||||
{
|
||||
//The ultimate subject of the connected bnode is this node's subject
|
||||
if (isset($bnodeMappings[$o]))
|
||||
{
|
||||
throw new Exception('Rdf bnode structure is not a tree');
|
||||
}
|
||||
$bnodeMappings[$o] = $s;
|
||||
//Transitively remap the subject of any child bnodes that were known
|
||||
foreach ($bnodeMappings as $mapFrom=>$mapTo)
|
||||
{
|
||||
if ($mapTo == $o)
|
||||
{
|
||||
$bnodeMappings[$mapFrom] = $s;
|
||||
}
|
||||
}
|
||||
if (isset($output[$o]))
|
||||
{
|
||||
$output[$s] = array_merge($output[$s],$output[$o]);
|
||||
unset($output[$o]);
|
||||
}
|
||||
}
|
||||
//Finished processing this statement
|
||||
}
|
||||
}
|
||||
//Statements are now organized by their ultimate subject. Do sanity checks: exactly one URI subject should be represented
|
||||
//in each key of the output array. Also convert URIs to wiki titles.
|
||||
$outputWithTitles = array();
|
||||
foreach ($output as $subject=>$statements)
|
||||
{
|
||||
$subjectfound = FALSE;
|
||||
foreach ($statements as $statement)
|
||||
{
|
||||
$s = $statement['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject'][0]['value'];
|
||||
$t = $statement['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject'][0]['type'];
|
||||
if ($t=='uri')
|
||||
{
|
||||
if ($s==$subject)
|
||||
{
|
||||
$subjectfound = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('RDF processing error: Two subjects per entity');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$subjectfound)
|
||||
{
|
||||
throw new Exception('RDF processing error: Bnode not connected to subject');
|
||||
}
|
||||
$outputWithTitles[AqueductInterface::uriToTitle($subject)] = $statements;
|
||||
}
|
||||
return $outputWithTitles;
|
||||
}
|
||||
|
||||
//Take a reified RDF ARC2 index, and create an un-reified index in its place.
|
||||
//Crashes if the original index contained any tree-like structures (reified statements about bnodes) because
|
||||
//this logic has not been coded yet
|
||||
public static function unReifyRDF($index)
|
||||
{
|
||||
//Look for reified RDF statements about the results
|
||||
$triples = array();
|
||||
foreach ($index as $nodeid=>$nodecontents)
|
||||
{
|
||||
if (isset($nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject']))
|
||||
{
|
||||
//This is a reified RDF statement
|
||||
$s = $nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject'][0]['value'];
|
||||
$t = $nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject'][0]['type'];
|
||||
$p = $nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate'][0]['value'];
|
||||
$o = $nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#object'][0]['value'];
|
||||
$ot = $nodecontents['http://www.w3.org/1999/02/22-rdf-syntax-ns#object'][0]['type'];
|
||||
|
||||
//Do not allow bnodes
|
||||
if ($t == 'bnode')
|
||||
{
|
||||
throw new Exception('RDF processing error: Blank nodes were found in the source data, and are not supported for this RDF operation.');
|
||||
}
|
||||
$triples []= array('s'=>$s,'p'=>$p,'o'=>$o,'s_type'=>'uri','o_type'=>$ot);
|
||||
}
|
||||
}
|
||||
aqProfile("arcUnReify");
|
||||
$retvalue = ARC2::getSimpleIndex($triples, false);
|
||||
aqProfile("aq");
|
||||
return $retvalue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Determine the Unicode codepoint of a single-character UTF-8 sequence.
|
||||
* Does not check for invalid input data.
|
||||
*
|
||||
* @param $char String
|
||||
* @return Integer
|
||||
* @public
|
||||
*/
|
||||
public static function utf8ToCodepoint( $char )
|
||||
{
|
||||
# Find the length
|
||||
$z = ord( $char{0} );
|
||||
if ( $z & 0x80 ) {
|
||||
$length = 0;
|
||||
while ( $z & 0x80 ) {
|
||||
$length++;
|
||||
$z <<= 1;
|
||||
}
|
||||
} else {
|
||||
$length = 1;
|
||||
}
|
||||
|
||||
if ( $length != strlen( $char ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( $length == 1 ) {
|
||||
return ord( $char );
|
||||
}
|
||||
|
||||
# Mask off the length-determining bits and shift back to the original location
|
||||
$z &= 0xff;
|
||||
$z >>= $length;
|
||||
|
||||
# Add in the free bits from subsequent bytes
|
||||
for ( $i=1; $i<$length; $i++ ) {
|
||||
$z <<= 6;
|
||||
$z |= ord( $char{$i} ) & 0x3f;
|
||||
}
|
||||
|
||||
return $z;
|
||||
}
|
||||
|
||||
public static function escapeSPARQLParameter($text)
|
||||
{
|
||||
//Insert the page name as a literal in the query where a double hash mark is seen
|
||||
//This is hard because the page name may contain characters that must be escaped
|
||||
//in a SPARQL literal.
|
||||
$n = str_replace('\\','\\\\',$text);
|
||||
$n = str_replace(array('"',"'"),array('\\"',"\\'"),$n);
|
||||
//Convert UTF-8 encoded codepoints into the appropriate SPARQL escape sequence
|
||||
$replace = '';
|
||||
$accum = '';
|
||||
for ($x=0;$x<strlen($n);$x++)
|
||||
{
|
||||
$c = $n[$x];
|
||||
if (ord($c)<128)
|
||||
{
|
||||
//Not a "unicode" character, can output literally
|
||||
$accum = '';
|
||||
$replace .= $c;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Try to decode UTF-8
|
||||
$accum .= $c;
|
||||
$codepoint = AqueductUtility::utf8ToCodepoint($accum);
|
||||
if ($codepoint!==false)
|
||||
{
|
||||
//Complete UTF-8 sequence found
|
||||
$seq = dechex($codepoint);
|
||||
while (strlen($seq)!=4 && strlen($seq)<8)
|
||||
{
|
||||
$seq = '0' . $seq;
|
||||
}
|
||||
if (strlen($seq)==4)
|
||||
{
|
||||
$seq = '\\u' . $seq;
|
||||
}
|
||||
else
|
||||
{
|
||||
$seq = '\\U' . $seq;
|
||||
}
|
||||
$replace .= $seq;
|
||||
$accum = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $replace;
|
||||
}
|
||||
}
|
||||
811
includes/SpecialAqueductConfiguration.php
Normal file
811
includes/SpecialAqueductConfiguration.php
Normal file
@@ -0,0 +1,811 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
require_once('extensions/AqueductExtension/includes/AqueductDbCalls.php');
|
||||
|
||||
class SpecialAqueductConfiguration extends SpecialPage
|
||||
{
|
||||
var $action;
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct( 'AqueductConfiguration','editinterface' );
|
||||
wfLoadExtensionMessages('AqueductExtension');
|
||||
$titleObj = Title::makeTitle( NS_SPECIAL, 'AqueductConfiguration' );
|
||||
$this->action = $titleObj->escapeLocalURL();
|
||||
}
|
||||
|
||||
// Takes in a row to be checked for validity before it is inserted. If the row is being modified, the old NS id and name are passed in.
|
||||
|
||||
// NOTE: that the functionality of this function is to return true if things complete properly and to toss an EXCEPTION if it fails
|
||||
// This is meant to be inside a catch block!
|
||||
protected function confirmBasicRow($row, $oldID = null, $oldName = null, $oldURI = null)
|
||||
{
|
||||
global $wgCanonicalNamespaceNames;
|
||||
|
||||
// Variable to hold all messages that will get thrown to the user.
|
||||
$errors = '';
|
||||
|
||||
// Flags for use at end of function. Documented there.
|
||||
$oldnsrm = false;
|
||||
|
||||
// Check that the namespace is a valid namespace.
|
||||
$legalcharpattern = '/^[A-Z][a-zA-Z0-9]*$/';
|
||||
// Check that the NS ID is even.
|
||||
if ($row['aq_wiki_namespace_id'] === '' || $row['aq_wiki_namespace_id'] % 2 !== 0)
|
||||
{
|
||||
$errors .= 'The namespace ID must be an even number.<br/>';
|
||||
}
|
||||
if ($row['aq_wiki_namespace'] === '' || !preg_match($legalcharpattern,$row['aq_wiki_namespace']))
|
||||
{
|
||||
$errors .= 'The namespace must be alphanumeric and start with a capital letter.<br/>';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if this is a modification.
|
||||
if ($oldID !== null && $oldName !== null)
|
||||
{
|
||||
// Modification case
|
||||
// If nothing changed in the NS id or name, don't bother looking further.
|
||||
if ($oldID !== $row['aq_wiki_namespace_id'] || $oldName !== $row['aq_wiki_namespace'])
|
||||
{
|
||||
// Otherwise...
|
||||
// If there is content in the NS, don't change!
|
||||
$pages = aqNSHasPages($row['aq_wiki_namespace_id']);
|
||||
if (empty($pages) === false)
|
||||
{
|
||||
$errors .= 'This namespace has active content and cannot be modified without abandoning pages. Delete all the pages in this namespace if you really want to modify it. Alternatively, you can delete this row and create a new one.<br/>';
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the name or id exist in oldns, give the "proper recycling" error
|
||||
$oldnsrows = aqDbTableGetAll('oldns');
|
||||
foreach ($oldnsrows as $oldnsrow)
|
||||
{
|
||||
if (($oldnsrow['aq_wiki_namespace_id'] === $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] !== $row['aq_wiki_namespace']) ||
|
||||
($oldnsrow['aq_wiki_namespace_id'] !== $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] === $row['aq_wiki_namespace']))
|
||||
{
|
||||
$errors .= 'The oldns row ['.$oldnsrow['aq_wiki_namespace_id'].'-'.$oldnsrow['aq_wiki_namespace'].'] must be properly recycled. Add a DIFFERENT row that matches both the ID *and* name of the oldns row you wish to recycle.<br/>';
|
||||
break;
|
||||
}
|
||||
|
||||
// If the values both match a row in the database, add it to the table and delete it from the oldns database
|
||||
else if ($oldnsrow['aq_wiki_namespace_id'] === $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] === $row['aq_wiki_namespace'])
|
||||
{
|
||||
// at this point this variable is a misnomer
|
||||
$oldnsrm = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($oldnsrm === false)
|
||||
{
|
||||
// check namespaces for a conflict.
|
||||
foreach ($wgCanonicalNamespaceNames as $id => $name)
|
||||
{
|
||||
if ($id == $row['aq_wiki_namespace_id'])
|
||||
{
|
||||
$errors .= 'This namespace ID already exists.<br/>';
|
||||
}
|
||||
if ($name === $row['aq_wiki_namespace'])
|
||||
{
|
||||
$errors .= 'This namespace already exists.<br/>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Addition case
|
||||
// Check oldns table for matches, if BOTH id and name match, flag for removal of row
|
||||
$oldnsrows = aqDbTableGetAll('oldns');
|
||||
foreach ($oldnsrows as $oldnsrow)
|
||||
{
|
||||
if (($oldnsrow['aq_wiki_namespace_id'] === $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] !== $row['aq_wiki_namespace']) ||
|
||||
($oldnsrow['aq_wiki_namespace_id'] !== $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] === $row['aq_wiki_namespace']))
|
||||
{
|
||||
$errors .= 'The oldns row ['.$oldnsrow['aq_wiki_namespace_id'].'-'.$oldnsrow['aq_wiki_namespace'].'] must be properly recycled. Add a DIFFERENT row that matches both the ID *and* name of the oldns row you wish to recycle.<br/>';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($oldnsrow['aq_wiki_namespace_id'] === $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] === $row['aq_wiki_namespace'])
|
||||
{
|
||||
$oldnsrm = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Else, check namespaces for a conflict
|
||||
if ($oldnsrm === false)
|
||||
{
|
||||
foreach ($wgCanonicalNamespaceNames as $id => $name)
|
||||
{
|
||||
if ($id == $row['aq_wiki_namespace_id'])
|
||||
{
|
||||
$errors .= 'This namespace ID already exists.<br/>';
|
||||
}
|
||||
if ($name == $row['aq_wiki_namespace'])
|
||||
{
|
||||
$errors .= 'This namespace already exists.<br/>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check the datastore uri prefix
|
||||
if ($row['aq_source_uri'] === '')
|
||||
{
|
||||
$errors .= 'Datastore URI prefix must not be empty.<br/>';
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this is a modification, check to see if the URI even changed before querying the database!
|
||||
if ($oldURI === null || $oldURI !== $row['aq_source_uri'])
|
||||
{
|
||||
$basicrows = aqDbTableGetAll();
|
||||
foreach ($basicrows as $basicrow)
|
||||
{
|
||||
// Check URI against those in the table.
|
||||
if ($basicrow['aq_source_uri'] === $row['aq_source_uri'])
|
||||
{
|
||||
$errors .= 'This datastore URI already exists in the standard Aqueduct table.<br/>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dsType = $row['aq_source_type'];
|
||||
|
||||
// Check if the location, cert path, and cert pass exist if type is not test.
|
||||
if ($dsType !== 'Test' && $dsType !== 'Embedded' && $dsType != 'Memcached' && $dsType != 'Arc2')
|
||||
{
|
||||
if ($row['aq_source_name'] === '' || $row['aq_source_location'] === '' || $row['aq_source_cert_path'] === '' || $row['aq_source_cert_pass'] === '')
|
||||
{
|
||||
$errors .= 'If the datastore type is not "Test" or "Embedded" or "Memcached" or "Arc2" then the Name, Location, Cert Path, and Cert Password must be included.<br/>';
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors === '')
|
||||
{
|
||||
// Check if the oldns row needs to be removed.
|
||||
if ($oldnsrm === true)
|
||||
{
|
||||
aqDbDeleteRow(array('aq_wiki_namespace_id'=>$oldnsrow['aq_wiki_namespace_id']), 'oldns');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('The following errors occured:<br/>' . $errors);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: that the functionality of this function is to return true if things complete properly and to toss an EXCEPTION if it fails.
|
||||
// This is meant to be inside a catch block!
|
||||
protected function confirmAdvancedRow($row, $oldID = null, $oldName = null)
|
||||
{
|
||||
global $wgCanonicalNamespaceNames;
|
||||
|
||||
|
||||
// Variable to hold all messages that will get thrown to the user.
|
||||
$errors = '';
|
||||
|
||||
// Flags for use at end of function. Documented there.
|
||||
$oldnsrm = false;
|
||||
|
||||
// Check that the NS ID is even.
|
||||
if ($row['aq_wiki_namespace_id'] === '' || $row['aq_wiki_namespace_id'] % 2 !== 0)
|
||||
{
|
||||
$errors .= 'The namespace ID must be an even number.<br/>';
|
||||
}
|
||||
|
||||
// Check that the namespace is a valid namespace.
|
||||
$legalcharpattern = '/^[A-Z][a-zA-Z0-9]*$/';
|
||||
$legalcharpatternsmall = '/^[a-zA-Z0-9]+$/';
|
||||
if (($row['aq_wiki_parent_namespace'] === '' || !preg_match($legalcharpattern,$row['aq_wiki_parent_namespace']))
|
||||
|| ($row['aq_wiki_namespace_tag'] === '' || !preg_match($legalcharpatternsmall,$row['aq_wiki_namespace_tag'])))
|
||||
{
|
||||
$errors .= 'The namespace must be alphanumeric and start with a capital letter.<br/>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$rows = aqDbTableGetAll();
|
||||
$found = false;
|
||||
foreach ($rows as $basicrow)
|
||||
{
|
||||
if ($basicrow['aq_wiki_namespace'] === $row['aq_wiki_parent_namespace'])
|
||||
{
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found === false)
|
||||
{
|
||||
$errors .= 'The associated namespace must match a namespace in the standard Aqueduct table.<br/>';
|
||||
}
|
||||
|
||||
// Check if this is a modification.
|
||||
if ($oldID !== null && $oldName !== null)
|
||||
{
|
||||
// Modification case
|
||||
// If nothing changed in the NS id or name, don't bother looking further.
|
||||
if ("$oldID" !== $row['aq_wiki_namespace_id'] || "$oldName" !== $row['aq_wiki_parent_namespace'].'_'.$row['aq_wiki_namespace_tag'])
|
||||
{
|
||||
// Otherwise...
|
||||
// If there is content in the NS, don't change!
|
||||
$pages = aqNSHasPages($row['aq_wiki_namespace_id']);
|
||||
if (empty($pages))
|
||||
{
|
||||
$errors .= 'This namespace has active content and cannot be modified without abandoning pages. Delete all the pages in this namespace if you really want to modify it. Alternatively, you can delete this row and create a new one.<br/>';
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the name or id exist in oldns, give the "proper recycling" error
|
||||
$oldnsrows = aqDbTableGetAll('oldns');
|
||||
foreach ($oldnsrows as $oldnsrow)
|
||||
{
|
||||
if (($oldnsrow['aq_wiki_namespace_id'] === $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] !== $row['aq_wiki_parent_namespace'].'_'.$row['aq_wiki_namespace_tag']) ||
|
||||
($oldnsrow['aq_wiki_namespace_id'] !== $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] === $row['aq_wiki_parent_namespace'].'_'.$row['aq_wiki_namespace_tag']))
|
||||
{
|
||||
$errors .= 'The oldns row ['.$oldnsrow['aq_wiki_namespace_id'].'-'.$oldnsrow['aq_wiki_namespace'].'] must be properly recycled. Add a DIFFERENT row that matches both the ID *and* name of the oldns row you wish to recycle.<br/>';
|
||||
break;
|
||||
}
|
||||
|
||||
// If this does match the oldns row, move it to the new row in this database
|
||||
if ($oldnsrow['aq_wiki_namespace_id'] === $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] === $row['aq_wiki_parent_namespace'].'_'.$row['aq_wiki_namespace_tag'])
|
||||
{
|
||||
$oldnsrm = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($oldnsrm === false)
|
||||
{
|
||||
// check namespaces for a conflict.
|
||||
foreach ($wgCanonicalNamespaceNames as $id => $name)
|
||||
{
|
||||
if ($id == $row['aq_wiki_namespace_id'])
|
||||
{
|
||||
$errors .= 'This namespace ID already exists.<br/>';
|
||||
}
|
||||
if ($name == $row['aq_wiki_parent_namespace'].'_'.$row['aq_wiki_namespace_tag'])
|
||||
{
|
||||
$errors .= 'This namespace already exists.<br/>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Addition case
|
||||
// Check oldns table for matches, if BOTH id and name match, flag for removal of row
|
||||
$oldnsrows = aqDbTableGetAll('oldns');
|
||||
foreach ($oldnsrows as $oldnsrow)
|
||||
{
|
||||
// check for the case when the id and name are mismatched
|
||||
if (($oldnsrow['aq_wiki_namespace_id'] === $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] !== $row['aq_wiki_parent_namespace'].'_'.$row['aq_wiki_namespace_tag']) ||
|
||||
($oldnsrow['aq_wiki_namespace_id'] !== $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] === $row['aq_wiki_parent_namespace'].'_'.$row['aq_wiki_namespace_tag']))
|
||||
{
|
||||
$errors .= 'The oldns row ['.$oldnsrow['aq_wiki_namespace_id'].'-'.$oldnsrow['aq_wiki_namespace'].'] must be properly recycled. Add a DIFFERENT row that matches both the ID *and* name of the oldns row you wish to recycle.<br/>';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($oldnsrow['aq_wiki_namespace_id'] === $row['aq_wiki_namespace_id'] &&
|
||||
$oldnsrow['aq_wiki_namespace'] === $row['aq_wiki_parent_namespace'].'_'.$row['aq_wiki_namespace_tag'])
|
||||
{
|
||||
$oldnsrm = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Else, check namespaces for a conflict
|
||||
if ($oldnsrm === false)
|
||||
{
|
||||
foreach ($wgCanonicalNamespaceNames as $id => $name)
|
||||
{
|
||||
if ($id == $row['aq_wiki_namespace_id'])
|
||||
{
|
||||
$errors .= 'This namespace ID already exists.<br/>';
|
||||
}
|
||||
if ($name == $row['aq_wiki_parent_namespace'].'_'.$row['aq_wiki_namespace_tag'])
|
||||
{
|
||||
$errors .= 'This namespace already exists.<br/>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check Query Type
|
||||
if ($row['aq_query_type'] !== 'ExecuteAlgorithm')
|
||||
{
|
||||
$errors .= 'The query type must be one of the following: ExecuteAlgorithm.<br/>';
|
||||
}
|
||||
|
||||
// Check Datasource Name
|
||||
if ($row['aq_datasource'] === '')
|
||||
{
|
||||
$errors .= 'The datastore name must be specified.<br/>';
|
||||
}
|
||||
|
||||
// Check the query
|
||||
if ($row['aq_query'] === '')
|
||||
{
|
||||
$errors .= 'The query must be specified.<br/>';
|
||||
}
|
||||
|
||||
if ($errors === '')
|
||||
{
|
||||
// Check if the oldns row needs to be removed.
|
||||
if ($oldnsrm === true)
|
||||
{
|
||||
aqDbDeleteRow(array('aq_wiki_namespace_id'=>$oldnsrow['aq_wiki_namespace_id']), 'oldns');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('The following errors occured:<br/>' . $errors);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// **********************************************
|
||||
// Actual start of the workhorse for the program
|
||||
// **********************************************
|
||||
public function execute()
|
||||
{
|
||||
global $wgOut, $wgUser, $wgRequest, $IP, $wgTitle;
|
||||
|
||||
// Declare the names of the columns in the databases.
|
||||
$uriColumns = array('aq_wiki_namespace_id',
|
||||
'aq_wiki_namespace',
|
||||
'aq_source_uri',
|
||||
'aq_source_type',
|
||||
'aq_source_name',
|
||||
'aq_source_location',
|
||||
'aq_source_cert_path',
|
||||
'aq_source_cert_pass',
|
||||
'aq_initial_lowercase',
|
||||
'aq_search_fragments');
|
||||
$queryColumns = array('aq_wiki_namespace_id',
|
||||
'aq_wiki_parent_namespace',
|
||||
'aq_wiki_namespace_tag',
|
||||
'aq_query_type',
|
||||
'aq_datasource',
|
||||
'aq_algorithm',
|
||||
'aq_query_uri_param',
|
||||
'aq_query');
|
||||
|
||||
// Declare the unique ID for the tables.
|
||||
$uriIDColumn = $uriColumns[0];
|
||||
$queryIDColumn = $queryColumns[0];
|
||||
|
||||
//Is the user trying to access the special page without permissions?
|
||||
//Even though the wiki omits the restricted special page from the special page list for users without permission, we must check here
|
||||
//in case the user accesses the page through a bookmark.
|
||||
if ( $this->userCanExecute( $wgUser ) )
|
||||
{
|
||||
//Process the previously posted commands
|
||||
foreach($_POST as $submitkey => $submitval)
|
||||
{
|
||||
if ($submitkey === "add_row_uri")
|
||||
{
|
||||
// Create an associative array to pass
|
||||
$values = array();
|
||||
$row = array();
|
||||
for ($i = 0; $i < sizeof($uriColumns); $i += 1)
|
||||
{
|
||||
$values[$i] = $_POST["new_uri_"."$uriColumns[$i]"];
|
||||
$row[$uriColumns[$i]] = $values[$i];
|
||||
}
|
||||
|
||||
// Checkboxes need a little modification
|
||||
if ($row['aq_initial_lowercase'] === NULL)
|
||||
{
|
||||
$row['aq_initial_lowercase'] = '0';
|
||||
}
|
||||
|
||||
if ($row['aq_search_fragments'] === NULL)
|
||||
{
|
||||
$row['aq_search_fragments'] = '0';
|
||||
}
|
||||
|
||||
try {
|
||||
$this->confirmBasicRow($row);
|
||||
aqDbInsertRow($row);
|
||||
} catch (Exception $e) {
|
||||
$wgOut->addHTML('<span style="color:red;">' . $e->getMessage() . '</span>');
|
||||
}
|
||||
}
|
||||
else if (strpos($submitkey,"delete_uri-") === 0)
|
||||
{
|
||||
$ID = substr($submitkey, 11);
|
||||
$name = $_POST['name-'.$ID];
|
||||
try {
|
||||
|
||||
// Make sure no query row relies on this namespace
|
||||
$advrows = aqDbTableGetAll('query');
|
||||
foreach ($advrows as $advrow)
|
||||
{
|
||||
// Check URI against those in the table.
|
||||
if ($advrow['aq_wiki_parent_namespace'] === $name)
|
||||
{
|
||||
$errors .= 'A row in the advanced query Aqueduct table relies on this row. Delete the row(s) that reference this namespace before deleting this row.<br/>';
|
||||
throw new Exception('The following errors occured:<br/>' . $errors);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if NS has pages, if so, add to oldns table
|
||||
$pages = aqNSHasPages($ID);
|
||||
if (empty($pages) === false)
|
||||
{
|
||||
aqDbInsertRow(array('aq_wiki_namespace_id'=>$ID, 'aq_wiki_namespace'=>$name), 'oldns');
|
||||
}
|
||||
|
||||
aqDbDeleteRow(array($uriIDColumn=>$ID));
|
||||
} catch (Exception $e) {
|
||||
$wgOut->addHTML('<span style="color:red;">' . $e->getMessage() . '</span>');
|
||||
}
|
||||
|
||||
}
|
||||
else if (strpos($submitkey,"modify_uri-") === 0)
|
||||
{
|
||||
$ID = substr($submitkey, 11);
|
||||
$name = null;
|
||||
$uri = null;
|
||||
$row = array();
|
||||
|
||||
for ($i = 0; $i < sizeof($uriColumns); $i += 1)
|
||||
$row[$uriColumns[$i]] = $_POST[$uriColumns[$i]."-".$ID];
|
||||
|
||||
if ($row['aq_initial_lowercase'] === NULL)
|
||||
{
|
||||
$row['aq_initial_lowercase'] = '0';
|
||||
}
|
||||
|
||||
if ($row['aq_search_fragments'] === NULL)
|
||||
{
|
||||
$row['aq_search_fragments'] = '0';
|
||||
}
|
||||
|
||||
$name = $_POST['name-'.$ID];
|
||||
$uri = $_POST['uri-'.$ID];
|
||||
|
||||
try {
|
||||
$this->confirmBasicRow($row, $ID, $name, $uri);
|
||||
aqDbReplaceRow(array($uriIDColumn=>$ID), $row);
|
||||
} catch (Exception $e) {
|
||||
$wgOut->addHTML('<span style="color:red;">' . $e->getMessage() . '</span>');
|
||||
}
|
||||
}
|
||||
else if ($submitkey === "add_row_query")
|
||||
{
|
||||
// Create an associative array to pass
|
||||
$values = array();
|
||||
$row = array();
|
||||
for ($i = 0; $i < sizeof($queryColumns); $i += 1)
|
||||
{
|
||||
$values[$i] = $_POST["new_query_"."$queryColumns[$i]"];
|
||||
$row[$queryColumns[$i]] = $values[$i];
|
||||
}
|
||||
|
||||
// Checkboxes need a little modification
|
||||
if ($row['aq_query_uri_param'] === NULL)
|
||||
{
|
||||
$row['aq_query_uri_param'] = '0';
|
||||
}
|
||||
|
||||
try {
|
||||
$this->confirmAdvancedRow($row, false);
|
||||
aqDbInsertRow($row, 'query');
|
||||
} catch (Exception $e) {
|
||||
$wgOut->addHTML('<span style="color:red;">' . $e->getMessage() . '</span>');
|
||||
}
|
||||
}
|
||||
else if (strpos($submitkey,"delete_query-") === 0)
|
||||
{
|
||||
$ID = substr($submitkey, 13);
|
||||
$name = $_POST['query_name-'.$ID];
|
||||
try {
|
||||
|
||||
// Check if NS has pages, if so, add to oldns table
|
||||
$pages = aqNSHasPages($ID);
|
||||
if (empty($pages) === false)
|
||||
{
|
||||
aqDbInsertRow(array('aq_wiki_namespace_id'=>$ID, 'aq_wiki_namespace'=>$name), 'oldns');
|
||||
}
|
||||
|
||||
aqDbDeleteRow(array($queryIDColumn=>$ID), 'query');
|
||||
} catch (Exception $e) {
|
||||
$wgOut->addHTML('<span style="color:red;">' . $e->getMessage() . '</span>');
|
||||
}
|
||||
}
|
||||
else if (strpos($submitkey,"modify_query-") === 0)
|
||||
{
|
||||
$ID = substr($submitkey, 13);
|
||||
$name = null;
|
||||
$row = array();
|
||||
|
||||
for ($i = 0; $i < sizeof($queryColumns); $i += 1)
|
||||
$row[$queryColumns[$i]] = $_POST[$queryColumns[$i]."-".$ID];
|
||||
|
||||
$name = $_POST["query_name-".$ID];
|
||||
|
||||
if ($row['aq_query_uri_param'] === NULL)
|
||||
{
|
||||
$row['aq_query_uri_param'] = '0';
|
||||
}
|
||||
|
||||
try {
|
||||
$this->confirmAdvancedRow($row, $ID, $name);
|
||||
aqDbReplaceRow(array($queryIDColumn=>$ID), $row, 'query');
|
||||
} catch (Exception $e) {
|
||||
$wgOut->addHTML('<span style="color:red;">' . $e->getMessage() . '</span>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//User is allowed to access the special page. Show the configuration table output.
|
||||
$this->setHeaders();
|
||||
$wgOut->addScript('<style type="text/css">input.aq,textarea {width:90%;} td {text-align:center} th {vertical-align:bottom}</style>');
|
||||
$wgOut->addHTML('<form name="aquaform" action="'.$this->action.'" method="post">');
|
||||
$wgOut->addHTML('<p>Columns marked with a * must be unique!</p>');
|
||||
$wgOut->addHTML('<table>');
|
||||
$wgOut->addHTML('<tr>');
|
||||
$wgOut->addHTML('<th>Wiki Namespace ID*</th>');
|
||||
$wgOut->addHTML('<th>Wiki Namespace*</th>');
|
||||
$wgOut->addHTML('<th>Datastore URI prefix*</th>');
|
||||
$wgOut->addHTML('<th>Datastore Type</th>');
|
||||
$wgOut->addHTML('<th>Datastore Name</th>');
|
||||
$wgOut->addHTML('<th>Datastore Location</th>');
|
||||
$wgOut->addHTML('<th>Datastore Certificate Path</th>');
|
||||
$wgOut->addHTML('<th>Certificate Password</th>');
|
||||
$wgOut->addHTML('<th>Title Initial Lowercase</th>');
|
||||
$wgOut->addHTML('<th>Search for Fragments</th>');
|
||||
$wgOut->addHTML('<th></th>');
|
||||
$wgOut->addHTML('<th></th>');
|
||||
$wgOut->addHTML('</tr>');
|
||||
|
||||
$rows = aqDbTableGetAll();
|
||||
foreach($rows as $row)
|
||||
{
|
||||
$rowID = $row[$uriIDColumn];
|
||||
$wgOut->addHTML("<tr>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_wiki_namespace_id'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='aq_wiki_namespace_id-$rowID' value='$value'></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_wiki_namespace'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='aq_wiki_namespace-$rowID' value='$value'></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_source_uri'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='aq_source_uri-$rowID' value='$value'></td>");
|
||||
|
||||
// A dropdown for items with specific answers
|
||||
$value = htmlspecialchars($row['aq_source_type'],ENT_QUOTES);
|
||||
|
||||
$wgOut->addHTML("<td><select name='aq_source_type-$rowID'>");
|
||||
$wgOut->addHTML("<option ".(($value === 'BB') ? "selected='selected'" : "")." value='BB'>BB</option>");
|
||||
$wgOut->addHTML("<option ".(($value === 'BB28') ? "selected='selected'" : "")." value='BB28'>BB28</option>");
|
||||
$wgOut->addHTML("<option ".(($value === 'BB30') ? "selected='selected'" : "")." value='BB30'>BB30</option>");
|
||||
$wgOut->addHTML("<option ".(($value === 'Test') ? "selected='selected'" : "")." value='Test'>Test</option>");
|
||||
$wgOut->addHTML("<option ".(($value === 'Embedded') ? "selected='selected'" : "")." value='Embedded'>Embedded</option>");
|
||||
$wgOut->addHTML("<option ".(($value === 'Memcached') ? "selected='selected'" : "")." value='Memcached'>Memcached</option>");
|
||||
$wgOut->addHTML("<option ".(($value === 'Arc2') ? "selected='selected'" : "")." value='Arc2'>Arc2</option>");
|
||||
$wgOut->addHTML("</select>");
|
||||
$wgOut->addHTML("</td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_source_name'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='aq_source_name-$rowID' value='$value'></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_source_location'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='aq_source_location-$rowID' value='$value'></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_source_cert_path'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='aq_source_cert_path-$rowID' value='$value'></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_source_cert_pass'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='aq_source_cert_pass-$rowID' value='$value'></td>");
|
||||
|
||||
// Checkboxes for the boolean values
|
||||
$value = htmlspecialchars($row['aq_initial_lowercase'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='checkbox' name='aq_initial_lowercase-$rowID' value='1' ".(($value === '1') ? "checked='yes'" : "")."/></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_search_fragments'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='checkbox' name='aq_search_fragments-$rowID' value='1' ".(($value === '1') ? "checked='yes'" : "")."/></td>");
|
||||
|
||||
$wgOut->addHTML("<td><input class='aq' type='submit' style='width:inherit' name='modify_uri-$rowID' value='Modify'/></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='submit' style='width:inherit' name='delete_uri-$rowID' value='Delete'/></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='hidden' name='name-$rowID' value='{$row['aq_wiki_namespace']}'/></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='hidden' name='uri-$rowID' value='{$row['aq_source_uri']}'/></td></tr>");
|
||||
}
|
||||
|
||||
$wgOut->addHTML("<tr>");
|
||||
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='new_uri_aq_wiki_namespace_id'></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='new_uri_aq_wiki_namespace'></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='new_uri_aq_source_uri'></td>");
|
||||
|
||||
// A dropdown for items with specific answers
|
||||
$wgOut->addHTML("<td><select name='new_uri_aq_source_type'>");
|
||||
$wgOut->addHTML("<option value='BB'>BB</option>");
|
||||
$wgOut->addHTML("<option value='BB28'>BB28</option>");
|
||||
$wgOut->addHTML("<option value='BB30'>BB30</option>");
|
||||
$wgOut->addHTML("<option value='Test'>Test</option>");
|
||||
$wgOut->addHTML("<option value='Embedded'>Embedded</option>");
|
||||
$wgOut->addHTML("<option value='Memcached'>Memcached</option>");
|
||||
$wgOut->addHTML("<option value='Arc2'>Arc2</option>");
|
||||
$wgOut->addHTML("</select>");
|
||||
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='new_uri_aq_source_name'></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='new_uri_aq_source_location'></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='new_uri_aq_source_cert_path'></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='new_uri_aq_source_cert_pass'></td>");
|
||||
|
||||
// Checkboxes for the boolean values
|
||||
$wgOut->addHTML("<td><input class='aq' type='checkbox' name='new_uri_aq_initial_lowercase' value='1'/></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='checkbox' name='new_uri_aq_search_fragments' value='1'/></td>");
|
||||
|
||||
$wgOut->addHTML("<td><input class='aq' type='submit' style='width:inherit' name='add_row_uri' value='Add'/></td></tr>");
|
||||
$wgOut->addHTML('</table>');
|
||||
$wgOut->addHTML('<br/><br/><br/>');
|
||||
|
||||
|
||||
// ***********************************************************
|
||||
//Show the configuration table output for the SPARQL queries.
|
||||
// ***********************************************************
|
||||
$wgOut->addHTML('<table>');
|
||||
$wgOut->addHTML('<tr>');
|
||||
$wgOut->addHTML('<th>New Namespace ID*</th>');
|
||||
$wgOut->addHTML('<th colspan="2">Associated Namespace<br/>& Query Tag</th>');
|
||||
$wgOut->addHTML('<th>Query Type</th>');
|
||||
$wgOut->addHTML('<th>Datastore Name</th>');
|
||||
$wgOut->addHTML('<th>Algorithm Name</th>');
|
||||
$wgOut->addHTML('<th>Use URI as Query Parameter</th>');
|
||||
$wgOut->addHTML('<th>Query Text</th>');
|
||||
$wgOut->addHTML('<th></th>');
|
||||
$wgOut->addHTML('<th></th>');
|
||||
$wgOut->addHTML('</tr>');
|
||||
|
||||
$rows = aqDbTableGetAll('query');
|
||||
foreach($rows as $row)
|
||||
{
|
||||
$rowID = $row[$uriIDColumn];
|
||||
$wgOut->addHTML("<tr>");
|
||||
|
||||
|
||||
$value = htmlspecialchars($row['aq_wiki_namespace_id'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='aq_wiki_namespace_id-$rowID' value='$value'/></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_wiki_parent_namespace'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='aq_wiki_parent_namespace-$rowID' value='$value'/></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_wiki_namespace_tag'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='aq_wiki_namespace_tag-$rowID' value='$value'/></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_query_type'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><select name='aq_query_type-$rowID'>");
|
||||
$wgOut->addHTML("<option ".(($value === 'ExecuteAlgorithm') ? "selected='selected'" : "")." value='ExecuteAlgorithm'>ExecuteAlgorithm</option>");
|
||||
$wgOut->addHTML("</select></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_datasource'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='aq_datasource-$rowID' value='$value'/></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_algorithm'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><select name='aq_algorithm-$rowID'>");
|
||||
$wgOut->addHTML("<option ".(($value === 'LuceneKeyword') ? "selected='selected'" : "")." value='LuceneKeyword'>LuceneKeyword</option>");
|
||||
$wgOut->addHTML("<option ".(($value === 'SparqlConstructQuery') ? "selected='selected'" : "")." value='SparqlConstructQuery'>SparqlConstructQuery</option>");
|
||||
$wgOut->addHTML("<option ".(($value === 'SparqlSelectQuery') ? "selected='selected'" : "")." value='SparqlSelectQuery'>SparqlSelectQuery</option>");
|
||||
$wgOut->addHTML("<option ".(($value === 'SparqlDescribeQuery') ? "selected='selected'" : "")." value='SparqlDescribeQuery'>SparqlDescribeQuery</option>");
|
||||
$wgOut->addHTML("</select></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_query_uri_param'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td><input class='aq' type='checkbox' name='aq_query_uri_param-$rowID' value='1' ".(($value === '1') ? "checked='yes'" : "")."/></td>");
|
||||
|
||||
$value = htmlspecialchars($row['aq_query'],ENT_QUOTES);
|
||||
$wgOut->addHTML("<td style='width:25%'><textarea rows='2' name='aq_query-$rowID'>$value</textarea></td>");
|
||||
|
||||
$wgOut->addHTML("<td><input class='aq' type='submit' style='width:inherit' name='modify_query-$rowID' value='Modify'/></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='submit' style='width:inherit' name='delete_query-$rowID' value='Delete'/></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='hidden' name='query_name-$rowID' value='{$row['aq_wiki_parent_namespace']}_{$row['aq_wiki_namespace_tag']}'/></td></tr>");
|
||||
}
|
||||
|
||||
$wgOut->addHTML('<tr>');
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='new_query_aq_wiki_namespace_id'/></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='new_query_aq_wiki_parent_namespace'/></td>");
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='new_query_aq_wiki_namespace_tag'/></td>");
|
||||
|
||||
$wgOut->addHTML("<td><select name='new_query_aq_query_type'>");
|
||||
$wgOut->addHTML("<option value='ExecuteAlgorithm'>ExecuteAlgorithm</option>");
|
||||
$wgOut->addHTML("</select></td>");
|
||||
|
||||
$wgOut->addHTML("<td><input class='aq' type='text' name='new_query_aq_datasource'/></td>");
|
||||
|
||||
$wgOut->addHTML("<td><select name='new_query_aq_algorithm'>");
|
||||
$wgOut->addHTML("<option value='LuceneKeyword'>LuceneKeyword</option>");
|
||||
$wgOut->addHTML("<option value='SparqlConstructQuery'>SparqlConstructQuery</option>");
|
||||
$wgOut->addHTML("<option value='SparqlSelectQuery'>SparqlSelectQuery</option>");
|
||||
$wgOut->addHTML("<option value='SparqlDescribeQuery'>SparqlDescribeQuery</option>");
|
||||
$wgOut->addHTML("</select></td>");
|
||||
|
||||
$wgOut->addHTML("<td><input class='aq' type='checkbox' name='new_query_aq_query_uri_param' value='1'/></td>");
|
||||
$wgOut->addHTML("<td style='width:25%'><textarea rows='2' name='new_query_aq_query'></textarea></td>");
|
||||
|
||||
$wgOut->addHTML("<td><input class='aq' type='submit' style='width:inherit' name='add_row_query' value='Add'/></td></tr>");
|
||||
$wgOut->addHTML('</table>');
|
||||
|
||||
$wgOut->addHTML('<br/><br/><br/>');
|
||||
|
||||
|
||||
$rows = aqDbTableGetAll('oldns');
|
||||
if (empty($rows) === false)
|
||||
{
|
||||
$wgOut->addHTML('<table>');
|
||||
$wgOut->addHTML('<tr>');
|
||||
$wgOut->addHTML('<th style="padding-right:10px">Old Namespace IDs</th>');
|
||||
$wgOut->addHTML('<th>Old Namespace Names</th>');
|
||||
$wgOut->addHTML('</tr>');
|
||||
|
||||
foreach($rows as $row)
|
||||
{
|
||||
$rowID = $row[0];
|
||||
$wgOut->addHTML("<tr>");
|
||||
$wgOut->addHTML("<td style='border:1px solid black'><span name='oldns_id-$rowID'>".htmlspecialchars($row[0],ENT_QUOTES)."</span></td>");
|
||||
$wgOut->addHTML("<td style='border:1px solid black'><span name='oldns_name-$rowID'>".htmlspecialchars($row[1],ENT_QUOTES)."</span></td>");
|
||||
}
|
||||
$wgOut->addHTML('</table>');
|
||||
}
|
||||
|
||||
$wgOut->addHTML('</form>');
|
||||
}
|
||||
else
|
||||
{
|
||||
//User is not allowed to see this page
|
||||
$this->displayRestrictionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
689
includes/WidgetTags.php
Normal file
689
includes/WidgetTags.php
Normal file
@@ -0,0 +1,689 @@
|
||||
<?php
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) )
|
||||
{
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
// Necessary to include this to be able to call up the Translation Table to pass to each page ONCE PER PAGE for the widgets.
|
||||
require_once('extensions/AqueductExtension/includes/AqueductDbCalls.php');
|
||||
|
||||
//Convenience function to extract the grid-mode height, width, and position parameters from the widget tag
|
||||
function aqWidgetGridParams($args, $data)
|
||||
{
|
||||
$data['height'] = ($args['height']===NULL?'':$args['height']);
|
||||
$data['width'] = ($args['width']===NULL?'':$args['width']);
|
||||
$data['position'] = ($args['position']===NULL?'':$args['position']);
|
||||
$data['resizable'] = ($args['resizable']===NULL?'':$args['resizable']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/// Widget tag to display the "Raw" skinned widget to a page.
|
||||
function aqRawWidgetTag($input, $args, $parser)
|
||||
{
|
||||
global $wgAqueductAccumWidgets, $wgAqueductJSFiles;
|
||||
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
|
||||
//First set the title.
|
||||
$myTitle = $parser->getTitle()->getPrefixedDBkey();
|
||||
|
||||
//JSON-encode the title so titles with special characters work
|
||||
$myJsonTitle = json_encode($myTitle);
|
||||
|
||||
//Set Widget data array.
|
||||
$wgtData = array('title' => $myJsonTitle, 'skin'=>'RawRDFCisternSkin');
|
||||
$wgtData = aqWidgetGridParams($args, $wgtData);
|
||||
|
||||
if (!isset($wgAqueductJSFiles))
|
||||
$wgAqueductJSFiles = array();
|
||||
|
||||
if (!isset($wgAqueductJSFiles['rawRdfSkin.js']))
|
||||
$wgAqueductJSFiles['rawRdfSkin.js'] = true;
|
||||
|
||||
//Check the accumulation variable.
|
||||
if(isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
//If it is set, add the data to the accumulation and do nothing else.
|
||||
$wgAqueductAccumWidgets[] = $wgtData;
|
||||
aqProfile('mw');
|
||||
}
|
||||
else
|
||||
{
|
||||
//If it is not set, then flush the widget to the page.
|
||||
return aqWidgetTagFlush($wgtData);
|
||||
}
|
||||
}
|
||||
|
||||
/// Widget tag to display the Table View widget to a page.
|
||||
function aqTableViewWidgetTag($input, $args, $parser)
|
||||
{
|
||||
global $wgAqueductAccumWidgets, $wgAqueductJSFiles;
|
||||
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
|
||||
//First set the title.
|
||||
$myTitle = $parser->getTitle()->getPrefixedDBkey();
|
||||
|
||||
//JSON-encode the title so titles with special characters work
|
||||
$myJsonTitle = json_encode($myTitle);
|
||||
|
||||
//Set Widget data array.
|
||||
$wgtData = array('title' => $myJsonTitle, 'skin'=>'TableViewCisternSkin');
|
||||
$wgtData = aqWidgetGridParams($args, $wgtData);
|
||||
|
||||
if (!isset($wgAqueductJSFiles))
|
||||
$wgAqueductJSFiles = array();
|
||||
|
||||
if (!isset($wgAqueductJSFiles['TableViewCisternSkin.js']))
|
||||
$wgAqueductJSFiles['TableViewCisternSkin.js'] = true;
|
||||
|
||||
//Check the accumulation variable.
|
||||
if(isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
//If it is set, add the data to the accumulation and do nothing else.
|
||||
$wgAqueductAccumWidgets[] = $wgtData;
|
||||
aqProfile('mw');
|
||||
}
|
||||
else
|
||||
{
|
||||
//If it is not set, then flush the widget to the page.
|
||||
return aqWidgetTagFlush($wgtData);
|
||||
}
|
||||
}
|
||||
|
||||
/// Widget tag to display the Google Map widget to a page.
|
||||
function aqNetworkViewWidgetTag($input, $args, $parser)
|
||||
{
|
||||
global $wgAqueductAccumWidgets, $wgAqueductJSFiles, $wgAqueductJSScripts, $wgJsMimeType, $wgGoogleAPIKey;
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
|
||||
//First set the title.
|
||||
$myTitle = $parser->getTitle()->getPrefixedDBkey();
|
||||
|
||||
//JSON-encode the title so titles with special characters work
|
||||
$myJsonTitle = json_encode($myTitle);
|
||||
|
||||
//Set Widget data array.
|
||||
$wgtData = array('title' => $myJsonTitle, 'skin'=>'NetworkViewSkin');
|
||||
$wgtData = aqWidgetGridParams($args, $wgtData);
|
||||
|
||||
if (!isset($wgAqueductJSFiles))
|
||||
$wgAqueductJSFiles = array();
|
||||
|
||||
if (!isset($wgAqueductJSScripts))
|
||||
$wgAqueductJSScripts = array();
|
||||
|
||||
if (!isset($wgAqueductJSScripts["<script type=\"{$wgJsMimeType}\" src=\"http://www.google.com/jsapi?key={$wgGoogleAPIKey}\"></script>\n"]))
|
||||
$wgAqueductJSScripts["<script type=\"{$wgJsMimeType}\" src=\"http://www.google.com/jsapi?key={$wgGoogleAPIKey}\"></script>\n"] = true;
|
||||
if (!isset($wgAqueductJSFiles['NetworkViewSkin.js']))
|
||||
$wgAqueductJSFiles['NetworkViewSkin.js'] = true;
|
||||
if (!isset($wgAqueductJSFiles['GoogleCore.js']))
|
||||
$wgAqueductJSFiles['GoogleCore.js'] = true;
|
||||
if (!isset($wgAqueductJSFiles['GoogleEarthPlugin.js']))
|
||||
$wgAqueductJSFiles['GoogleEarthPlugin.js'] = true;
|
||||
|
||||
//Check the accumulation variable.
|
||||
if(isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
//If it is set, add the data to the accumulation and do nothing else.
|
||||
$wgAqueductAccumWidgets[] = $wgtData;
|
||||
aqProfile('mw');
|
||||
}
|
||||
else
|
||||
{
|
||||
//If it is not set, then flush the widget to the page.
|
||||
return aqWidgetTagFlush($wgtData);
|
||||
}
|
||||
}
|
||||
|
||||
/// Widget tag to display the Google Map widget to a page.
|
||||
function aqNetworkViewWidget2DTag($input, $args, $parser)
|
||||
{
|
||||
global $wgAqueductAccumWidgets, $wgAqueductJSFiles, $wgAqueductJSScripts, $wgJsMimeType, $wgGoogleAPIKey;
|
||||
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
|
||||
//First set the title.
|
||||
$myTitle = $parser->getTitle()->getPrefixedDBkey();
|
||||
|
||||
//JSON-encode the title so titles with special characters work
|
||||
$myJsonTitle = json_encode($myTitle);
|
||||
|
||||
//Set Widget data array.
|
||||
$wgtData = array('title' => $myJsonTitle, 'skin'=>'NetworkViewSkin2D');
|
||||
$wgtData = aqWidgetGridParams($args, $wgtData);
|
||||
|
||||
if (!isset($wgAqueductJSFiles))
|
||||
$wgAqueductJSFiles = array();
|
||||
|
||||
if (!isset($wgAqueductJSScripts))
|
||||
$wgAqueductJSScripts = array();
|
||||
|
||||
if (!isset($wgAqueductJSScripts['<script type="'.$wgJsMimeType.'" src="http://maps.google.com/maps?file=api&v=2.x&key='.$wgGoogleAPIKey.'&sensor=false"></script>']))
|
||||
$wgAqueductJSScripts['<script type="'.$wgJsMimeType.'" src="http://maps.google.com/maps?file=api&v=2.x&key='.$wgGoogleAPIKey.'&sensor=false"></script>'] = true;
|
||||
if (!isset($wgAqueductJSFiles['NetworkViewSkin2D.js']))
|
||||
$wgAqueductJSFiles['NetworkViewSkin2D.js'] = true;
|
||||
|
||||
//Check the accumulation variable.
|
||||
if(isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
//If it is set, add the data to the accumulation and do nothing else.
|
||||
$wgAqueductAccumWidgets[] = $wgtData;
|
||||
aqProfile('mw');
|
||||
}
|
||||
else
|
||||
{
|
||||
//If it is not set, then flush the widget to the page.
|
||||
return aqWidgetTagFlush($wgtData);
|
||||
}
|
||||
}
|
||||
|
||||
/// Tag to define a user-defined widget layout
|
||||
function aqLayoutTag($input, $args, $parser)
|
||||
{
|
||||
global $wgAqueductAccumWidgets, $wgCurrentLayout;
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
|
||||
//Set Widget data array.
|
||||
$wgtData = array('skin'=>'Layout');
|
||||
|
||||
//Remember what the active layout is
|
||||
$wgCurrentLayout = $input;
|
||||
|
||||
//Check the accumulation variable.
|
||||
if(isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
//If it is set, add the data to the accumulation and do nothing else.
|
||||
$wgAqueductAccumWidgets[] = $wgtData;
|
||||
aqProfile('mw');
|
||||
}
|
||||
else
|
||||
{
|
||||
//If it is not set, then immediately apply the layout
|
||||
return aqWidgetTagFlush($wgtData);
|
||||
}
|
||||
}
|
||||
|
||||
/// Widget tag to display a user-defined widget on the page, using the last processed layout.
|
||||
function aqLayoutWidgetTag($input, $args, $parser)
|
||||
{
|
||||
global $wgAqueductAccumWidgets,$wgAqueductJSFiles;
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
|
||||
//First set the title.
|
||||
$myTitle = $parser->getTitle()->getPrefixedDBkey();
|
||||
|
||||
//JSON-encode the title so titles with special characters work
|
||||
$myJsonTitle = json_encode($myTitle);
|
||||
|
||||
//Set Widget data array.
|
||||
$wgtData = array('title' => $myJsonTitle, 'skin'=>'LayoutSkin');
|
||||
$wgtData = aqWidgetGridParams($args, $wgtData);
|
||||
|
||||
if (!$wgAqueductJSFiles)
|
||||
$wgAqueductJSFiles = array();
|
||||
if (!isset($wgAqueductJSFiles['TemplateCisternSkin.js']))
|
||||
$wgAqueductJSFiles['TemplateCisternSkin.js'] = true;
|
||||
if (!isset($wgAqueductJSFiles['jquery-jtemplates.js']))
|
||||
$wgAqueductJSFiles['jquery-jtemplates.js'] = true;
|
||||
|
||||
//Check the accumulation variable.
|
||||
if(isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
//If it is set, add the data to the accumulation and do nothing else.
|
||||
$wgAqueductAccumWidgets[] = $wgtData;
|
||||
aqProfile('mw');
|
||||
}
|
||||
else
|
||||
{
|
||||
//If it is not set, then flush the widget to the page.
|
||||
return aqWidgetTagFlush($wgtData);
|
||||
}
|
||||
}
|
||||
|
||||
// Tag to mark the wikitext position when using grid mode
|
||||
function aqWikiTextTag($input, $args, $parser)
|
||||
{
|
||||
global $wgAqueductAccumWidgets,$wgAqueductJSFiles,$wgAqueductLayoutMode;
|
||||
|
||||
aqProfile('aq');
|
||||
if ($wgAqueductLayoutMode)
|
||||
{
|
||||
$parser->disableCache();
|
||||
|
||||
//Set Widget data array.
|
||||
$wgtData = array('skin'=>'WikiText');
|
||||
$wgtData = aqWidgetGridParams($args, $wgtData);
|
||||
|
||||
//Check the accumulation variable.
|
||||
if(isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
//If it is set, add the data to the accumulation and do nothing else.
|
||||
$wgAqueductAccumWidgets[] = $wgtData;
|
||||
aqProfile('mw');
|
||||
}
|
||||
else
|
||||
{
|
||||
//If it is not set, then flush the widget to the page.
|
||||
return aqWidgetTagFlush($wgtData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Widget tag to add a custom header
|
||||
function aqHeaderTag($input, $args, $parser)
|
||||
{
|
||||
global $wgAqueductAccumWidgets, $wgAqueductJSFiles;
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
|
||||
//First set the title.
|
||||
$myTitle = $parser->getTitle()->getPrefixedDBkey();
|
||||
|
||||
//JSON-encode the title so titles with special characters work
|
||||
$myJsonTitle = json_encode($myTitle);
|
||||
|
||||
//Set Widget data array.
|
||||
$wgtData = array('title' => $myJsonTitle, 'skin' => 'CustomHeader');
|
||||
|
||||
if (!isset($wgAqueductJSFiles))
|
||||
$wgAqueductJSFiles = array();
|
||||
|
||||
if (!isset($wgAqueductJSFiles[$input]))
|
||||
$wgAqueductJSFiles[$input] = true;
|
||||
|
||||
//Check the accumulation variable.
|
||||
if(isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
//If it is set, add the data to the accumulation and do nothing else.
|
||||
$wgAqueductAccumWidgets[] = $wgtData;
|
||||
aqProfile('mw');
|
||||
}
|
||||
else
|
||||
{
|
||||
//If it is not set, then flush the widget to the page.
|
||||
return aqWidgetTagFlush($wgtData);
|
||||
}
|
||||
}
|
||||
|
||||
/// Widget tag to add a custom script
|
||||
function aqScriptTag($input, $args, $parser)
|
||||
{
|
||||
global $wgAqueductAccumWidgets, $wgAqueductJSScripts;
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
|
||||
//First set the title.
|
||||
$myTitle = $parser->getTitle()->getPrefixedDBkey();
|
||||
|
||||
//JSON-encode the title so titles with special characters work
|
||||
$myJsonTitle = json_encode($myTitle);
|
||||
|
||||
//Set Widget data array.
|
||||
$wgtData = array('title' => $myJsonTitle, 'skin' => 'CustomScript' );
|
||||
|
||||
if (!isset($wgAqueductJSScripts))
|
||||
$wgAqueductJSScripts = array();
|
||||
|
||||
if (!isset($wgAqueductJSScripts['<script type="text/javascript"> '.$input.' </script>']))
|
||||
$wgAqueductJSScripts['<script type="text/javascript"> '.$input.' </script>'] = true;
|
||||
|
||||
//Check the accumulation variable.
|
||||
if(isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
//If it is set, add the data to the accumulation and do nothing else.
|
||||
$wgAqueductAccumWidgets[] = $wgtData;
|
||||
aqProfile('mw');
|
||||
}
|
||||
else
|
||||
{
|
||||
//If it is not set, then flush the widget to the page.
|
||||
return aqWidgetTagFlush($wgtData);
|
||||
}
|
||||
}
|
||||
|
||||
/// Core function that flushes all widgets in the buffer for this page to the page view.
|
||||
function aqWidgetTagFlush($wgtData = NULL)
|
||||
{
|
||||
global $wgAqueductLayoutMode, $wgCurrentLayout, $wgOut, $wgServer, $wgScriptPath, $wgAqueductDivNumber, $wgAqueductJSFiles, $wgAqueductJSScripts, $wgAqueductAccumWidgets, $wgAqueductDataAdded, $wgAqueductQueryAdded;
|
||||
|
||||
// Check to make sure we are not in a Data Inclusion API call. If so, get out.
|
||||
if (isset($wgAqueductDataAdded) || isset($wgAqueductQueryAdded))
|
||||
{
|
||||
aqProfile('mw');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Widget div number initialization.
|
||||
if (!$wgAqueductDivNumber)
|
||||
$wgAqueductDivNumber = 1;
|
||||
|
||||
// if wgtData is null, use the accum widgets array.
|
||||
//If they are both set or unset, this is a failstate.
|
||||
if ($wgtData != NULL && !isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
$widgetsArray = array($wgtData);
|
||||
}
|
||||
else if ($wgtData == NULL && isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
$widgetsArray = $wgAqueductAccumWidgets;
|
||||
}
|
||||
else
|
||||
{
|
||||
aqProfile('mw');
|
||||
return 'A fatal error has occurred in an Aqueduct Widget on this page. Please contact your Wiki Administrator.';
|
||||
}
|
||||
|
||||
// Add widget-insensitive core scripts.
|
||||
if (!isset($wgAqueductJSFiles['jquery-1.3.2.min.js']))
|
||||
{
|
||||
$wgAqueductJSFiles['jquery-1.3.2.min.js'] = false;
|
||||
$wgOut->addScriptFile($wgScriptPath. '/extensions/AqueductExtension/widget/js/jquery-1.3.2.min.js');
|
||||
}
|
||||
if (!isset($wgAqueductJSFiles['widgetCore.js']))
|
||||
{
|
||||
$wgAqueductJSFiles['widgetCore.js'] = false;
|
||||
$wgOut->addScriptFile($wgScriptPath. '/extensions/AqueductExtension/widget/js/widgetCore.js');
|
||||
}
|
||||
|
||||
// Add the aqueduct namespace translation table to the javascript, allowing the JS uri->title functionality.
|
||||
$rows = aqDbTableGetAll();
|
||||
$jsonrows = array();
|
||||
|
||||
foreach ($rows as $row => $vals)
|
||||
{
|
||||
$jsonvals = array();
|
||||
$jsonvals['aq_source_uri'] = $vals['aq_source_uri'];
|
||||
$jsonvals['aq_initial_lowercase'] = $vals['aq_initial_lowercase'];
|
||||
$jsonvals['aq_wiki_namespace_id'] = $vals['aq_wiki_namespace_id'];
|
||||
$jsonvals['aq_wiki_namespace'] = $vals['aq_wiki_namespace'];
|
||||
$jsonrows []= $jsonvals;
|
||||
//For security, don't pass anything else to the browser
|
||||
}
|
||||
|
||||
// JSON the array
|
||||
$data = json_encode($jsonrows);
|
||||
|
||||
// Add the json array to the page as a head script.
|
||||
if (!isset($wgAqueductJSScripts['<script type="text/javascript">/*<![CDATA[*/var aqTransTable = '.$data.'/*]]>*/</script>']))
|
||||
{
|
||||
$wgAqueductJSScripts['<script type="text/javascript">/*<![CDATA[*/var aqTransTable = '.$data.'/*]]>*/</script>'] = false;
|
||||
$wgOut->addScript('<script type="text/javascript">/*<![CDATA[*/var aqTransTable = '.$data.'/*]]>*/</script>' . "\n");
|
||||
}
|
||||
|
||||
// If we are in grid mode, init the widget list that the grid-construction code in the skin will read
|
||||
if ($wgAqueductLayoutMode && !isset($wgAqueductJSScripts['<script type="text/javascript">/*<![CDATA[*/var aqWidgetList = []; /*]]>*/</script>']))
|
||||
{
|
||||
$wgAqueductJSScripts['<script type="text/javascript">/*<![CDATA[*/var aqWidgetList = []; /*]]>*/</script>'] = false;
|
||||
$wgOut->addScript('<script type="text/javascript">/*<![CDATA[*/var aqWidgetList = []; /*]]>*/</script>' . "\n");
|
||||
}
|
||||
|
||||
$output = '';
|
||||
|
||||
foreach ($wgAqueductJSScripts as $script => &$trigger)
|
||||
{
|
||||
if ($trigger == true)
|
||||
{
|
||||
$wgOut->addScript($script . "\n");
|
||||
$trigger = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Dump the needed JS files and scripts;
|
||||
foreach ($wgAqueductJSFiles as $file => &$trigger)
|
||||
{
|
||||
if ($trigger == true)
|
||||
{
|
||||
$wgOut->addScriptFile($wgScriptPath. '/extensions/AqueductExtension/widget/js/' . $file);
|
||||
$trigger = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Go through the Widgets on this page and flush their data to the page.
|
||||
foreach ($widgetsArray as $data)
|
||||
{
|
||||
$templatejson = 'null';
|
||||
if (isset($wgCurrentLayout))
|
||||
{
|
||||
$templatejson = json_encode($wgCurrentLayout);
|
||||
}
|
||||
if ($data['skin'] == 'WikiText' && $wgAqueductLayoutMode)
|
||||
{
|
||||
//This is the wikitext position marker for layout mode
|
||||
$wgOut->addScript('<script type="text/javascript">'."\n"
|
||||
. 'aqWidgetList.push([null,null,null,null,null,'
|
||||
. json_encode($data['position']).','
|
||||
. json_encode($data['height']).','
|
||||
. json_encode($data['width']) . ','
|
||||
. 'true' . ','
|
||||
. json_encode($data['resizable'])
|
||||
. ']);'
|
||||
. "</script>\n");
|
||||
}
|
||||
else if($data['skin'] != 'CustomHeader' && $data['skin'] != 'CustomScript' && $data['skin'] != 'Layout')
|
||||
{
|
||||
//If we are in grid mode, let the Javascript construct the widget divs, instead of doing it right away
|
||||
if ($wgAqueductLayoutMode)
|
||||
{
|
||||
$wgOut->addScript('<script type="text/javascript">'."\n"
|
||||
. 'aqWidgetList.push(["'
|
||||
. $data['skin'].'","'
|
||||
. $wgServer.$wgScriptPath.'/api.php",'
|
||||
. $data['title'].','
|
||||
. $data['title'].','
|
||||
. $templatejson.','
|
||||
. json_encode($data['position']).','
|
||||
. json_encode($data['height']).','
|
||||
. json_encode($data['width']) . ','
|
||||
. 'false'. ','
|
||||
. json_encode($data['resizable'])
|
||||
. ']);'
|
||||
. "</script>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Put up script block with the widget call
|
||||
$wgOut->addScript('<script type="text/javascript">'."\n\t\t\t"
|
||||
. 'initialQuery = '.$data['title']."\n\t\t\t"
|
||||
. 'fullQuery = '.$data['title']."\n\t\t\t"
|
||||
. 'template = '.$templatejson."\n\t\t\t"
|
||||
. 'widget'.$wgAqueductDivNumber.' = new CisternWidget("AqueductDiv'.$wgAqueductDivNumber.'", "'.$data['skin'].'", "'.$wgServer.$wgScriptPath.'/api.php", initialQuery, fullQuery, template,false)'."\n\t\t"
|
||||
. "</script>\n");
|
||||
|
||||
// Put out the Div for the widget in this page.
|
||||
$output .= "<div id=\"AqueductDiv".$wgAqueductDivNumber."\" name=\"AqueductDiv".$wgAqueductDivNumber."\" style=\"border:1px solid #B0B0B0; background-color:#FFFFFF; padding:5px; margin:10px; float:left\"> </div>";
|
||||
// autoincrement to keep div IDs unique
|
||||
$wgAqueductDivNumber += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
aqProfile('mw');
|
||||
return $output;
|
||||
}
|
||||
|
||||
/// Tag function to recursively include widgets from other pages.
|
||||
function aqIncludeWidgetsTag($input, $args, $parser)
|
||||
{
|
||||
global $wgAqueductAccumWidgets, $wgAqueductPagesSeen;
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
|
||||
// Initialize the PagesSeen array if it doesn't exist.
|
||||
if (!isset($wgAqueductPagesSeen))
|
||||
$wgAqueductPagesSeen = array();
|
||||
|
||||
// Tell the widgets to accumulate instead of printing straight away.
|
||||
// Otherwise, continue on with recursion.
|
||||
if (!isset($wgAqueductAccumWidgets))
|
||||
{
|
||||
$wgAqueductAccumWidgets = array();
|
||||
$entryPoint = true;
|
||||
$myTitle = json_encode($parser->getTitle()->getPrefixedDBkey());
|
||||
$wgAqueductPagesSeen["$myTitle"] = true;
|
||||
}
|
||||
|
||||
// Make a Title object for the page you're recursing to.
|
||||
$wgtTitle = Title::newFromText($input);
|
||||
|
||||
// Add the page we are recursing to to the pages seen.
|
||||
// Otherwise, we need to break this tree of recursions.
|
||||
if($wgAqueductPagesSeen["$wgtTitle"] != true)
|
||||
{
|
||||
$wgAqueductPagesSeen["$wgtTitle"] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create an article object that points to the page.
|
||||
$wgtArticle = new Article($wgtTitle);
|
||||
|
||||
// Get the contents of the page template transclusion style.
|
||||
$wgtTags = $wgtArticle->getContent();
|
||||
|
||||
// Return the parsed widget tags to display the widgets.
|
||||
$oldTitle = $parser->getTitle();
|
||||
|
||||
// Instantiate a new parser to use.
|
||||
$wgtParser = new Parser();
|
||||
wfAqueductSetParserHooks($wgtParser);
|
||||
$wgtParser->disableCache();
|
||||
|
||||
// Recurse to the page we need to include.
|
||||
$wgtParser->parse($wgtTags, $wgtTitle, $parser->Options());
|
||||
aqProfile('aq');
|
||||
|
||||
// Reset this so that other include tags will work.
|
||||
$wgAqueductPagesSeen["$wgtTitle"] = false;
|
||||
|
||||
if ($entryPoint == true)
|
||||
{
|
||||
$output = aqWidgetTagFlush();
|
||||
// Unset only works locally. Unless you do this.
|
||||
unset($GLOBALS['wgAqueductAccumWidgets']);
|
||||
$wgAqueductPagesSeen["$myTitle"] = false;
|
||||
aqProfile('mw');
|
||||
return $output;
|
||||
}
|
||||
else
|
||||
{
|
||||
aqProfile('mw');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Tag to handle the Data inclusion case, where one widget displays many pages' data.
|
||||
function aqAddDataTag($input, $args, $parser)
|
||||
{
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
global $wgAqueductDataAdded;
|
||||
|
||||
// Check to make sure we are in a Data Inclusion API call. If not, get out.
|
||||
if (!isset($wgAqueductDataAdded))
|
||||
{
|
||||
aqProfile('mw');
|
||||
return '';
|
||||
}
|
||||
|
||||
// Create the title object
|
||||
$dataTitle = Title::newFromText($input);
|
||||
|
||||
// Add title object to the array
|
||||
if ($dataTitle !== NULL)
|
||||
{
|
||||
//Only add it if the title didn't have any syntax errors in it
|
||||
$wgAqueductDataAdded[] = $dataTitle;
|
||||
}
|
||||
aqProfile('mw');
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
// Inline SPARQL queries to allow a widget on a page to display arbitrary SPARQL.
|
||||
function aqAddQueryTag($input, $args, $parser)
|
||||
{
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
global $wgAqueductQueryAdded;
|
||||
|
||||
// Check to make sure we are in a Query API call. If not, get out
|
||||
if (!isset($wgAqueductQueryAdded))
|
||||
{
|
||||
aqProfile('mw');
|
||||
return '';
|
||||
}
|
||||
|
||||
$queryColumns = array(
|
||||
'aq_wiki_namespace_id', //Namespace ID: Assumed by the call; not needed in the parameters.
|
||||
'aq_wiki_parent_namespace', //Namespace: Namespace of the query to be made in; not needed in the parameters.
|
||||
'aq_wiki_namespace_tag', //Query Tag: Query tag used to reference the row in database; not needed in the parameters.
|
||||
'aq_query_type', //Query Type: Type of query to be made; To be passed as a parameter.
|
||||
'aq_datasource', //Datasource: Datasource to query against; To be passed as a parameter.
|
||||
'aq_algorithm', //Algorithm: Algorithm used by the query; To be passed as a parameter.
|
||||
'aq_query_uri_param', //URI as param: Boolean to say whether title is used as param; To be passed as a parameter.
|
||||
'aq_query' //Query Text: Actual body of the query; Taken through $input.
|
||||
);
|
||||
|
||||
// Generate the 'row' to mimic the rows in the database.
|
||||
$queryrow = array();
|
||||
$myTitle = Title::newFromText($args['namespace'] . ':Query');
|
||||
$queryrow["$queryColumns[0]"] = $myTitle->getNamespace();
|
||||
$queryrow["$queryColumns[1]"] = $args['namespace'];
|
||||
$queryrow["$queryColumns[2]"] = '';
|
||||
$queryrow["$queryColumns[3]"] = $args['type'];
|
||||
$queryrow["$queryColumns[4]"] = $args['datasource'];
|
||||
$queryrow["$queryColumns[5]"] = $args['algorithm'];
|
||||
$queryrow["$queryColumns[6]"] = $args['uriasparam'];
|
||||
$queryrow["$queryColumns[7]"] = $input;
|
||||
|
||||
$wgAqueductQueryAdded[] = $queryrow;
|
||||
aqProfile('mw');
|
||||
return '';
|
||||
}
|
||||
|
||||
//Allows RDF triples to be directly embedded in a page
|
||||
function aqAddTripleTag( &$parser, $predicate, $object, $objecttype=NULL, $fragment=NULL )
|
||||
{
|
||||
aqProfile('aq');
|
||||
$parser->disableCache();
|
||||
global $wgAqueductTriplesAdded;
|
||||
//Don't activate this unless we are specifically checking for these triples.
|
||||
if (!isset($wgAqueductTriplesAdded))
|
||||
{
|
||||
aqProfile('mw');
|
||||
return '';
|
||||
}
|
||||
$wgAqueductTriplesAdded []=
|
||||
array('fragment' => $fragment, 'object' => $object, 'predicate' => $predicate, 'objecttype' => $objecttype);
|
||||
aqProfile('mw');
|
||||
return '';
|
||||
}
|
||||
339
license.txt
Normal file
339
license.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
78
siphon.html
Normal file
78
siphon.html
Normal file
@@ -0,0 +1,78 @@
|
||||
<html><body>
|
||||
|
||||
<h2><a name="AqueductDocumentation-1.2-Siphon"></a>Siphon</h2>
|
||||
|
||||
<p>Siphon is a software package that mirrors the semantic data in a Semantic Mediawiki wiki into one or more Blackbook datasources.</p>
|
||||
|
||||
<p>Siphon is composed of two components -- the intake extension and the Blackbook feeder. The intake extension captures data from Semantic Mediawiki and outputs it to a queue folder. The Blackbook feeder process reads files from the queue folder and sends the data to Blackbook.</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Settingupthequeuefolder"></a>Setting up the queue folder</h3>
|
||||
|
||||
<p>The siphon intake extension communicates with the Blackbook feeder through a queue folder where RDF files are placed. The queue folder must be local to the machine where the intake extension and the Blackbook feeder process are running (not on an NFS volume). This means that the Blackbook feeder process and the queue folder must be located on the same machine where the wiki is. (However, Blackbook itself can be running on a different machine.)</p>
|
||||
|
||||
<p>To set up the queue folder, create a directory that can be read and written by both the Apache process (for Mediawiki) and the Blackbook feeder process.</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Settinguptheintakeextension"></a>Setting up the intake extension</h3>
|
||||
|
||||
<ol>
|
||||
<li>Copy the SiphonIntakeExtension directory to the "extensions" folder of your Mediawiki installation.</li>
|
||||
<li>Make sure that Semantic Mediawiki is installed and fully functional</li>
|
||||
<li>Add the following line to LocalSettings.php: $wgAutoloadClasses['SMWSiphonStore'] = "$IP/extensions/SiphonIntakeExtension/SMW_SiphonStore.php";</li>
|
||||
|
||||
<li>LocalSettings.php should already have a "enableSemantics" line from the Semantic Mediawiki installation. Ensure that you are passing appropriate parameters to the enableSemantics line so Semantic Mediawiki generates appropriate URIs for your semantic pages. The default settings often result in unexpectedly long and complicated URIs. A line similar to "enableSemantics('url:mywiki:',true);" will cause short URIs such as "url:mywiki:TestPage" to be generated, which may be what you want.</li>
|
||||
<li>Add the following line to LocalSettings.php, substituting the queue folder that you set up: $wgSiphonQueueDirectory = '/var/myqueue';</li>
|
||||
<li>Open the SMW_Settings.php file for your Semantic Mediawiki installation. You should see a line that says $smwgDefaultStore = "SMWSQLStore2"; . Change the "SMWSQLStore2" to "SMWSiphonStore".</li>
|
||||
<li>Ensure that the namespaces that you want to use are in the $smwgNamespacesWithSemanticLinks array in SMW_Settings.php. A common source of problems is forgetting to add a namespace to smwgNamespacesWithSemanticLinks when you create a namespace on the Aqueduct configuration special page and expect Siphon to pick up the semantic data.</li>
|
||||
<li>Ensure that RAP is installed and included. To do this, download RAP to a directory accessible to the wiki and add something similar to the following to LocalSettings.php:</li>
|
||||
</ol>
|
||||
|
||||
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
|
||||
<pre class="code-java">define('RDFAPI_INCLUDE_DIR', $IP.'/extensions/rdfapi-php/api/');
|
||||
include(RDFAPI_INCLUDE_DIR . <span class="code-quote">"RdfAPI.php"</span>);
|
||||
require_once(RDFAPI_INCLUDE_DIR . 'util/RdfUtil.php');
|
||||
include(RDFAPI_INCLUDE_DIR . PACKAGE_SYNTAX_RDF);</pre>
|
||||
</div></div>
|
||||
<p>Now, verify that make changes to semantic pages in the wiki causes files to appear in the queue directory. The files should contain the RDF for the semantic data that you added.</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-SettingupBlackbook"></a>Setting up Blackbook</h3>
|
||||
|
||||
<p>Create / Modify the target Data Source such that the following options are filled out in the Blackbook Metadata Manager under Modify Data Source/ Add Data Source page for the specific data source (refer to latest BB version documentation for in depth instructions of how to complete this stage):</p>
|
||||
<ul>
|
||||
<li>Max merge docs: 1000 (this is sort of a magical number that you may have to modify but must be larger than Merger Factor)</li>
|
||||
|
||||
<li>Merge factor: 100 (like above this info may be found in Jena documentation or BB2 docs at a later stage)</li>
|
||||
<li>Type: Assertions</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-SettinguptheBlackbookfeeder%26nbsp%3B"></a>Setting up the Blackbook feeder </h3>
|
||||
|
||||
<p>Put the BBSiphonFeeder folder in the directory of your choosing. Examples are /opt, /usr/local, or the users home directory.</p>
|
||||
|
||||
<p>Ensure that the folder that will contain the rdf data to be ingested into Blackbook has permissions equal to the user that will set up this application.<br/>
|
||||
|
||||
Run the bbSiphonStartupScript.sh script with the following command line arguments:<br/>
|
||||
./bbSiphonStartupScript.sh periodicity of execution of application(in seconds), fully qualified absolute filepath to bb2Feeder.php(do not use ~ or the like, not dependable), fully qualified absolute filepath to rdf folder, Blackbook server url, path to BB certificate file, BB Certificate Passphrase, path to User's public key file, fully qualified absolute filepath to rdf backup folder, blackbook version number (2 or 3).</p>
|
||||
|
||||
<p>Note that there are two certificates required to use BB3 -- the BB certificate and the user's public key. The BB certificate should be in PEM format (you can use the same file that you used in Aqueduct for the BB Proxy certificate). The user's public key should be the certificate that you install in your web browser to use Aqueduct, converted to PEM (encoded into ASCII characters), and without the associated private key attached.</p>
|
||||
|
||||
<p>If you are using BB2, the public key file is ignored, and can contain dummy content. </p>
|
||||
|
||||
<p>One way to generate the public key file is to generate a test .php page that dumps the SERVER variables, and then add this test page to a web server running https. When you send the client certificate from your browser, the public key will show up in the SERVER variables.</p>
|
||||
|
||||
<p>One common source of problems is having the wrong style of line breaks in the public key file. If the file has improper line break characters, Blackbook will fail to set the user, with a generic error message.</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Initializingthesemanticdata"></a>Initializing the semantic data</h3>
|
||||
|
||||
<p>At first, any pre-existing semantic data will be missing from the Blackbook datasource. To resolve this, force the wiki to re-process all of the semantic data by going to the Admin Functions for Semantic MediaWiki page and starting the "Data repair and upgrade" function. This will start a Mediawiki job that will dump the semantic contents of the wiki into the queue. To force the process to complete more quickly, run the runJobs.php script from the maintenance folder of the Mediawiki installation.</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Operationofthesiphon"></a>Operation of the siphon</h3>
|
||||
|
||||
<p>Because semantic data is placed in the queue directory for later consumption, it is okay to use the wiki while Blackbook or the Blackbook feeder is down. RDF files will accumulate in the queue directory, and will be processed when Blackbook comes back up.</p>
|
||||
|
||||
<p>However, the presence of the queue in the Siphon system means that there will be a short lag time between editing the wiki and seeing the changes in Blackbook. Keep this in mind in applications where users or agents will be frequently reading and writing semantic data to the wiki.</p>
|
||||
|
||||
<h3><a name="AqueductDocumentation-1.2-Usingmultiplequeuedirectories"></a>Using multiple queue directories</h3>
|
||||
|
||||
<p>To send the data from one wiki to multiple Blackbook installations, use multiple queue directories, with one feeder process per Blackbook installation. Do not point multiple feeder processes at the same queue directory. To specify multiple queue directories in LocalSettings.php, use array() to set the $wgSiphonQueueDirectory variable to an array of queue directories instead of a string.</p>
|
||||
</body></html>
|
||||
63
widget/js/GoogleCore.js
Normal file
63
widget/js/GoogleCore.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
// Shared Google API
|
||||
function __global_googleInit()
|
||||
{
|
||||
|
||||
jQuery(document).ready(function() {
|
||||
// init widgets
|
||||
if (___CisternWidgetInstances)
|
||||
{
|
||||
___CisternWidgetInstances[0].OnLoadAll()
|
||||
}
|
||||
});
|
||||
|
||||
for (var x in gm_registry)
|
||||
{
|
||||
gm_registry[x].map = new google.maps.Map2(gm_registry[x].innerDiv.attr("id"))
|
||||
gm_registry[x].map.setCenter(new google.maps.LatLng(gm_registry[x].lat, gm_registry[x].lon), 13)
|
||||
gm_registry[x].gmInitCallback()
|
||||
}
|
||||
|
||||
for (var x in ge_registry)
|
||||
{
|
||||
// doesn't perserve the object association with the init callback here
|
||||
//google.earth.createInstance(ge_registry[x].innerDiv.attr("id"), ge_registry[x].geInitCallback, global_geFailureCallback)
|
||||
google.earth.createInstance(ge_registry[x].innerDiv.attr("id"), ge_registry[x].initcallback, global_geFailureCallback)
|
||||
//google.earth.createInstance(ge_registry[x].innerDiv.attr("id"), global_geInitCallback, global_geFailureCallback)
|
||||
}
|
||||
}
|
||||
|
||||
//google.load("jquery", "1.2.6");
|
||||
|
||||
google.setOnLoadCallback(__global_googleInit)
|
||||
|
||||
var ge_registry = []
|
||||
var gm_registry = []
|
||||
|
||||
function global_geInitCallback(instance) {
|
||||
for (x in ge_registry)
|
||||
{
|
||||
ge_registry[x].geInitCallback(instance)
|
||||
}
|
||||
}
|
||||
|
||||
function global_geFailureCallback(instance) {
|
||||
//console.debug("in geFailureCallback")
|
||||
}
|
||||
19
widget/js/GoogleEarthPlugin.js
Normal file
19
widget/js/GoogleEarthPlugin.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
google.load("earth", "1")
|
||||
410
widget/js/NetworkViewSkin.js
Normal file
410
widget/js/NetworkViewSkin.js
Normal file
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
// Constructor
|
||||
function NetworkViewSkin(div, baseWidget, useInitialQuery){
|
||||
this.ge = false
|
||||
this.lat = 40.7494
|
||||
this.lon = -73.9681
|
||||
this.data = false
|
||||
this.page_subject = baseWidget.initialQuery
|
||||
this.placemarks = []
|
||||
|
||||
this.placemarksToAdd = []
|
||||
this.linesToAdd = []
|
||||
|
||||
this.icons = {}
|
||||
this.visitedNodes = {}
|
||||
|
||||
this.div = jQuery("#"+div)
|
||||
this.baseWidget = baseWidget
|
||||
this.useInitialQuery = useInitialQuery
|
||||
|
||||
this.loadingDiv = jQuery('<div><img src="'+wgScriptPath+'/extensions/AqueductExtension/widget/js/ajax-loader.gif" alt="Loading..." /></div>').css("display", "none")
|
||||
this.loadingDiv.css("position", "absolute").css("float", "left").css("z-index", 1000)
|
||||
this.div.before(this.loadingDiv)
|
||||
|
||||
this.div.width(500)
|
||||
this.div.height(500)
|
||||
|
||||
this.innerDiv = jQuery('<div id="' + baseWidget.divName + '_innerdiv"></div>')
|
||||
|
||||
this.innerDiv.width(500)
|
||||
this.innerDiv.height(500)
|
||||
|
||||
this.div.append(this.innerDiv)
|
||||
|
||||
this.inQuery = false
|
||||
|
||||
ge_registry.push(this)
|
||||
|
||||
var me = this;
|
||||
|
||||
// closure to stop the google api from losing a reference to our class
|
||||
this.initcallback = function(instance) {
|
||||
me.ge = instance;
|
||||
me.ge.getWindow().setVisibility(true);
|
||||
|
||||
// nav controls
|
||||
me.ge.getNavigationControl().setVisibility(me.ge.VISIBILITY_AUTO);
|
||||
|
||||
// set layers
|
||||
me.ge.getLayerRoot().enableLayerById(me.ge.LAYER_BORDERS, true);
|
||||
me.ge.getLayerRoot().enableLayerById(me.ge.LAYER_ROADS, false);
|
||||
|
||||
|
||||
me.ge.getOptions().setStatusBarVisibility(true);
|
||||
me.ge.getOptions().setScaleLegendVisibility(true);
|
||||
|
||||
// Get the current view
|
||||
var lookAt = me.ge.getView().copyAsLookAt(me.ge.ALTITUDE_RELATIVE_TO_GROUND);
|
||||
|
||||
// Set lat and long
|
||||
lookAt.setLatitude(me.lat);
|
||||
lookAt.setLongitude(me.lon);
|
||||
lookAt.setTilt(lookAt.getTilt() + 20.0);
|
||||
|
||||
lookAt.setRange(lookAt.getRange() * 0.4);
|
||||
|
||||
// Update the view in Google Earth
|
||||
me.ge.getView().setAbstractView(lookAt);
|
||||
|
||||
me.TryRender()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NetworkViewSkin.prototype.InitGE = function() {
|
||||
google.earth.createInstance('map3d', this.geInitCallback, this.geFailureCallback);
|
||||
}
|
||||
|
||||
|
||||
NetworkViewSkin.prototype.constructLabel = function(entity, preds)
|
||||
{
|
||||
var label = "";
|
||||
|
||||
|
||||
var uriLink = uriToTitle(entity)
|
||||
|
||||
// hack to get root wiki directory
|
||||
var temp = document.location.href.split("index.php")
|
||||
|
||||
label += '<a href="' + temp[0] + "index.php/" + uriLink + '">' + uriLink + '</a><br/>'
|
||||
|
||||
|
||||
// build up tooltip label here
|
||||
if ("http://www.w3.org/2000/01/rdf-schema#label" in this.data[subject])
|
||||
{
|
||||
label += "Label: " +String(this.data[subject]["http://www.w3.org/2000/01/rdf-schema#label"].object[0]) + "<br/>"
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.placeAndDraw = function(subject){
|
||||
var place
|
||||
var plat = false
|
||||
var plon = false
|
||||
var color = "ffffffff"
|
||||
var width = 2
|
||||
var label = ""
|
||||
|
||||
if (this.visitedNodes[subject]){
|
||||
|
||||
if (this.placemarks[subject])
|
||||
return this.placemarks[subject]
|
||||
else
|
||||
return false
|
||||
}
|
||||
else
|
||||
{
|
||||
if ("http://www.w3.org/2003/01/geo/wgs84_pos#long" in this.data[subject])
|
||||
{
|
||||
if (!plon)
|
||||
plon = []
|
||||
|
||||
for (var index in this.data[subject]["http://www.w3.org/2003/01/geo/wgs84_pos#long"].object)
|
||||
{
|
||||
plon.push(parseFloat(this.data[subject]["http://www.w3.org/2003/01/geo/wgs84_pos#long"].object[index]))
|
||||
}
|
||||
}
|
||||
if ("http://www.w3.org/2003/01/geo/wgs84_pos#lat" in this.data[subject])
|
||||
{
|
||||
if (!plat)
|
||||
plat = []
|
||||
|
||||
for (var index in this.data[subject]["http://www.w3.org/2003/01/geo/wgs84_pos#lat"].object)
|
||||
{
|
||||
plat.push(parseFloat(this.data[subject]["http://www.w3.org/2003/01/geo/wgs84_pos#lat"].object[index]))
|
||||
}
|
||||
}
|
||||
if ("scar:color" in this.data[subject])
|
||||
color = String(this.data[subject]["scar:color"].object[0])
|
||||
if ("scar:edgewidth" in this.data[subject])
|
||||
width = String(this.data[subject]["scar:edgewidth"].object[0])
|
||||
|
||||
label = this.constructLabel(subject, this.data[subject])
|
||||
|
||||
if (plat && plon ){
|
||||
if (plat.length == plon.length){
|
||||
|
||||
for(var index in plon){
|
||||
|
||||
if (subject in this.placemarks)
|
||||
place = this.placemarks[subject][0]
|
||||
else{
|
||||
// This also seems to do nothing, as no value is returned from this function. I hope this.placemarks is not being used to render, because it has a big undefined where the place should be.
|
||||
place = this.addPlace(plat[index], plon[index], subject, label)
|
||||
}
|
||||
}
|
||||
|
||||
this.placemarks[subject] = [place, {lat:plat, lon:plon}]
|
||||
}
|
||||
}
|
||||
|
||||
this.visitedNodes[subject] = subject
|
||||
}
|
||||
|
||||
// find resource links and follow them
|
||||
for (var predicate in this.data[subject])
|
||||
{
|
||||
if (this.data[subject][predicate].objType == "uri")
|
||||
{
|
||||
// could be multiple uris
|
||||
for (var linkedIndex in this.data[subject][predicate].object)
|
||||
{
|
||||
|
||||
var linkeduri = this.data[subject][predicate].object[linkedIndex]
|
||||
|
||||
if (linkeduri in this.data)
|
||||
{
|
||||
// if the link had lat/long draw it
|
||||
var ret = this.placeAndDraw(linkeduri)
|
||||
if (ret)
|
||||
{
|
||||
if (plat.length == plon.length)
|
||||
{
|
||||
for(var index in plon)
|
||||
{
|
||||
for (var index2 in ret[1].lat)
|
||||
{
|
||||
// Connect the dots
|
||||
this.addConnect({lat:plat[index], lon:plon[index]}, {lat:ret[1].lat[index2],lon:ret[1].lon[index2]}, width, color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.placemarks[subject])
|
||||
return this.placemarks[subject]
|
||||
else
|
||||
return false
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.geFailureCallback = function (errorCode) {
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.makePlace = function (placeLat, placeLon, placeName, placeDesc)
|
||||
{
|
||||
return this.makePlaceIcon(placeLat, placeLon, placeName, placeDesc, "http://maps.google.com/mapfiles/kml/paddle/red-circle.png", 1.0)
|
||||
}
|
||||
NetworkViewSkin.prototype.makePlaceIcon = function (placeLat, placeLon, placeName, placeDesc, iconHref)
|
||||
{
|
||||
return this.makePlaceIconStyle(placeLat, placeLon, placeName, placeDesc, iconHref, 1.0)
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.addPlace = function (placeLat, placeLon, placeName, placeDesc)
|
||||
{
|
||||
return this.addPlaceIcon(placeLat, placeLon, placeName, placeDesc, "http://maps.google.com/mapfiles/kml/paddle/red-circle.png", 1.0)
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.addPlaceIcon = function (placeLat, placeLon, placeName, placeDesc, iconHref)
|
||||
{
|
||||
return this.addPlaceIconStyle(placeLat, placeLon, placeName, placeDesc, iconHref, 1.0)
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.addPlaceIconStyle = function (placeLat, placeLon, placeName, placeDesc, iconHref, iconScale) {
|
||||
this.placemarksToAdd.push([placeLat, placeLon, placeName, placeDesc, iconHref, iconScale])
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.batchDraw = function (){
|
||||
for (var skin in ge_registry)
|
||||
{
|
||||
// placemarks
|
||||
for (var p in ge_registry[skin].placemarksToAdd)
|
||||
{
|
||||
ge_registry[skin].makePlaceIconStyle(ge_registry[skin].placemarksToAdd[p][0], ge_registry[skin].placemarksToAdd[p][1], ge_registry[skin].placemarksToAdd[p][2], ge_registry[skin].placemarksToAdd[p][3], ge_registry[skin].placemarksToAdd[p][4], ge_registry[skin].placemarksToAdd[p][5])
|
||||
}
|
||||
|
||||
// lines
|
||||
for (var l in ge_registry[skin].linesToAdd)
|
||||
{
|
||||
ge_registry[skin].connect(ge_registry[skin].linesToAdd[l][0], ge_registry[skin].linesToAdd[l][1], ge_registry[skin].linesToAdd[l][2], ge_registry[skin].linesToAdd[l][3])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.makePlaceIconStyle = function makePlaceIconStyle(placeLat, placeLon, placeName, placeDesc, iconHref, iconScale) {
|
||||
var placemark = this.ge.createPlacemark('');
|
||||
placemark.setName(placeName);
|
||||
placemark.setDescription(placeDesc);
|
||||
this.ge.getFeatures().appendChild(placemark);
|
||||
|
||||
var style
|
||||
if (this.icons[iconHref])
|
||||
style = this.icons[iconHref]
|
||||
else{
|
||||
// Define a custom icon.
|
||||
var icon = this.ge.createIcon('');
|
||||
icon.setHref(iconHref);
|
||||
var style = this.ge.createStyle('');
|
||||
style.getIconStyle().setIcon(icon);
|
||||
style.getIconStyle().setScale(iconScale);
|
||||
this.icons[iconHref] = style
|
||||
}
|
||||
|
||||
placemark.setStyleSelector(style);
|
||||
|
||||
var point = this.ge.createPoint('');
|
||||
point.setLatitude(placeLat);
|
||||
point.setLongitude(placeLon);
|
||||
placemark.setGeometry(point);
|
||||
|
||||
return placemark
|
||||
}
|
||||
|
||||
|
||||
NetworkViewSkin.prototype.addConnect = function (start, stop, width, color){
|
||||
this.linesToAdd.push([start, stop, width, color])
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.connect = function (start, stop, width, color){
|
||||
var placemark = this.ge.createPlacemark('')
|
||||
placemark.setStyleSelector(this.ge.createStyle(''));
|
||||
|
||||
var lineStyle = placemark.getStyleSelector().getLineStyle();
|
||||
lineStyle.setWidth(width);
|
||||
lineStyle.getColor().set(color);
|
||||
|
||||
placemark.setGeometry(this.shootLine(start, stop))
|
||||
|
||||
this.ge.getFeatures().appendChild(placemark);
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.shootLine = function (start, stop){
|
||||
var ring = this.ge.createLineString('');
|
||||
|
||||
ring.setTessellate(true);
|
||||
ring.setExtrude(false);
|
||||
|
||||
var steps = 50;
|
||||
|
||||
// clamp to ground
|
||||
ring.setAltitudeMode(this.ge.ALTITUDE_CLAMP_TO_GROUND);
|
||||
ring.getCoordinates().pushLatLngAlt(start.lat, start.lon, 0)
|
||||
ring.getCoordinates().pushLatLngAlt(stop.lat, stop.lon, 0)
|
||||
|
||||
return ring;
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.Destroy = function(){
|
||||
this.div = null
|
||||
this.baseWidget = null
|
||||
this.loadingDiv = null
|
||||
this.innerDiv = null
|
||||
this.selectbox = null
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.OnOutputTypeChange = function(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
NetworkViewSkin.prototype.QueryStarted = function(){
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.QueryError = function(error)
|
||||
{
|
||||
this.innerDiv.text("There was an error while making the AJAX call:" + error);
|
||||
// leave this.inQuery mode
|
||||
this.inQuery = false;
|
||||
this.loadingDiv.css("display", "none");
|
||||
this.div.css("background-color", "white");
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.QuerySuccess = function(isInitial, response)
|
||||
{
|
||||
this.data = response
|
||||
|
||||
// make a record object that traverses easier
|
||||
this.data = this.CreateIndexedJSONRDF()
|
||||
|
||||
this.TryRender()
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.CreateIndexedJSONRDF = function()
|
||||
{
|
||||
var indexedJSONRDF = {}
|
||||
|
||||
for (record in this.data['records'])
|
||||
{
|
||||
var subject = {}
|
||||
for(entityName in this.data['records'][record]['entityNames'])
|
||||
{
|
||||
indexedJSONRDF[this.data['records'][record]['entityNames'][entityName]] = subject
|
||||
}
|
||||
for(predicate in this.data['records'][record]['fieldValues'])
|
||||
{
|
||||
var statement = {}
|
||||
|
||||
var urisInPath = predicate.split(" ");
|
||||
subject[urisInPath[urisInPath.length - 1]] = statement;
|
||||
|
||||
statement.object = this.data['records'][record]['fieldValues'][predicate]
|
||||
|
||||
if (this.data['records'][record]['fieldValues'][predicate].objType == "uri")
|
||||
{
|
||||
// I have a hunch uriToTitle will break if object is an Array
|
||||
var uriLink = uriToTitle(statement.object)
|
||||
statement.objectlink = decodeURIComponent(uriLink).link(uriLink)
|
||||
}
|
||||
|
||||
statement.role = this.data['records'][record]['fieldValues'][predicate].role
|
||||
}
|
||||
}
|
||||
|
||||
return indexedJSONRDF
|
||||
}
|
||||
|
||||
NetworkViewSkin.prototype.TryRender = function(obj) {
|
||||
if (this.ge && this.data ){
|
||||
// good ol' loop for unconnected segments graph traversal
|
||||
for (subject in this.data)
|
||||
{
|
||||
this.placeAndDraw(subject)
|
||||
}
|
||||
|
||||
// mega hack to suspend rendering of globe while we draw
|
||||
// its a performance booster, believe it or not. (batches the inserts)
|
||||
google.earth.fetchKml(this.ge, '', this.batchDraw);
|
||||
}
|
||||
}
|
||||
338
widget/js/NetworkViewSkin2D.js
Normal file
338
widget/js/NetworkViewSkin2D.js
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
// USE: The Tableview Skin dumps entities into their own row, and
|
||||
|
||||
// Constructor
|
||||
function NetworkViewSkin2D(div, baseWidget, useInitialQuery){
|
||||
this.map = "";
|
||||
this.lat = 40.7494
|
||||
this.lon = -73.9681
|
||||
this.data = ""
|
||||
this.page_subject = baseWidget.initialQuery
|
||||
this.placemarks = []
|
||||
|
||||
this.placemarksToAdd = []
|
||||
this.linesToAdd = []
|
||||
|
||||
this.icons = {}
|
||||
this.visitedNodes = {}
|
||||
|
||||
this.div = jQuery("#"+div)
|
||||
this.baseWidget = baseWidget
|
||||
this.useInitialQuery = useInitialQuery
|
||||
|
||||
this.div.width(712)
|
||||
this.div.height(400)
|
||||
|
||||
this.innerDiv = jQuery('<div id="' + baseWidget.divName + '_innerdiv"></div>')
|
||||
|
||||
this.innerDiv.width(712)
|
||||
this.innerDiv.height(400)
|
||||
|
||||
this.div.append(this.innerDiv)
|
||||
|
||||
this.inQuery = false
|
||||
|
||||
this.gmInitCallback()
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.gmInitCallback = function() {
|
||||
this.map = new GMap2(this.innerDiv[0]);
|
||||
this.map.setCenter(new GLatLng(45.828799,-105.292969), 2);
|
||||
this.map.addControl(new GSmallMapControl());
|
||||
|
||||
this.TryRender()
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.constructLabel = function(entity, preds)
|
||||
{
|
||||
var label = "";
|
||||
|
||||
|
||||
var uriLink = uriToTitle(entity)
|
||||
|
||||
// root wiki directory
|
||||
// XXX: Should probably use wgScript
|
||||
var temp = document.location.href.split("index.php")
|
||||
|
||||
label += '<a href="' + temp[0] + "index.php/" + uriLink + '">' + uriLink + '</a><br/>'
|
||||
|
||||
|
||||
// build up tooltip label here
|
||||
if ("http://www.w3.org/2000/01/rdf-schema#label" in this.data[subject])
|
||||
{
|
||||
label += "Label: " +String(this.data[subject]["http://www.w3.org/2000/01/rdf-schema#label"].object[0]) + "<br/>"
|
||||
}
|
||||
return label;
|
||||
}
|
||||
NetworkViewSkin2D.prototype.placeAndDraw = function(subject){
|
||||
var place
|
||||
var plat = false
|
||||
var plon = false
|
||||
var color = "ffffffff"
|
||||
var width = 2
|
||||
var label = ""
|
||||
|
||||
if (this.visitedNodes[subject]){
|
||||
if (this.placemarks[subject])
|
||||
return this.placemarks[subject]
|
||||
else
|
||||
return false
|
||||
}
|
||||
else
|
||||
{
|
||||
if ("http://www.w3.org/2003/01/geo/wgs84_pos#long" in this.data[subject])
|
||||
{
|
||||
if (!plon)
|
||||
plon = []
|
||||
|
||||
for (var index in this.data[subject]["http://www.w3.org/2003/01/geo/wgs84_pos#long"].object)
|
||||
{
|
||||
this.lon = parseFloat(this.data[subject]["http://www.w3.org/2003/01/geo/wgs84_pos#long"].object[index]);
|
||||
plon.push(this.lon);
|
||||
}
|
||||
}
|
||||
if ("http://www.w3.org/2003/01/geo/wgs84_pos#lat" in this.data[subject])
|
||||
{
|
||||
if (!plat)
|
||||
plat = []
|
||||
|
||||
for (var index in this.data[subject]["http://www.w3.org/2003/01/geo/wgs84_pos#lat"].object)
|
||||
{
|
||||
this.lat = parseFloat(this.data[subject]["http://www.w3.org/2003/01/geo/wgs84_pos#lat"].object[index]);
|
||||
plat.push(this.lat)
|
||||
}
|
||||
}
|
||||
if ("scar:color" in this.data[subject])
|
||||
color = String(this.data[subject]["scar:color"].object[0])
|
||||
if ("scar:edgewidth" in this.data[subject])
|
||||
width = String(this.data[subject]["scar:edgewidth"].object[0])
|
||||
|
||||
label = this.constructLabel(subject, this.data[subject])
|
||||
|
||||
if (plat && plon ){
|
||||
if (plat.length == plon.length){
|
||||
|
||||
for(var index in plon){
|
||||
|
||||
if (subject in this.placemarks)
|
||||
place = this.placemarks[subject][0]
|
||||
else{
|
||||
// This also seems to do nothing, as no value is returned from this function.
|
||||
place = this.addPlace(plat[index], plon[index], subject, label)
|
||||
}
|
||||
}
|
||||
|
||||
this.placemarks[subject] = [place, {lat:plat, lon:plon}]
|
||||
}
|
||||
}
|
||||
|
||||
this.visitedNodes[subject] = subject
|
||||
}
|
||||
|
||||
// find resource links and follow them
|
||||
for (var predicate in this.data[subject])
|
||||
{
|
||||
if (this.data[subject][predicate].objType == "uri")
|
||||
{
|
||||
// could be multiple uris
|
||||
for (var linkedIndex in this.data[subject][predicate].object)
|
||||
{
|
||||
|
||||
var linkeduri = this.data[subject][predicate].object[linkedIndex]
|
||||
|
||||
if (linkeduri in this.data)
|
||||
{
|
||||
// if the link had lat/long draw it
|
||||
var ret = this.placeAndDraw(linkeduri)
|
||||
if (ret)
|
||||
{
|
||||
if (plat.length == plon.length)
|
||||
{
|
||||
for(var index in plon)
|
||||
{
|
||||
for (var index2 in ret[1].lat)
|
||||
{
|
||||
// Connect the dots
|
||||
this.addConnect({lat:plat[index], lon:plon[index]}, {lat:ret[1].lat[index2],lon:ret[1].lon[index2]}, width, color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.placemarks[subject])
|
||||
return this.placemarks[subject]
|
||||
else
|
||||
return false
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.makePlace = function (placeLat, placeLon, placeName, placeDesc)
|
||||
{
|
||||
return this.makePlaceIcon(placeLat, placeLon, placeName, placeDesc, "http://maps.google.com/mapfiles/kml/paddle/red-circle.png", 1.0)
|
||||
}
|
||||
NetworkViewSkin2D.prototype.makePlaceIcon = function (placeLat, placeLon, placeName, placeDesc, iconHref)
|
||||
{
|
||||
return this.makePlaceIconStyle(placeLat, placeLon, placeName, placeDesc, iconHref, 1.0)
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.addPlace = function (placeLat, placeLon, placeName, placeDesc){
|
||||
return this.addPlaceIcon(placeLat, placeLon, placeName, placeDesc, "http://maps.google.com/mapfiles/kml/paddle/red-circle.png", 1.0)
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.addPlaceIcon = function (placeLat, placeLon, placeName, placeDesc, iconHref)
|
||||
{
|
||||
return this.addPlaceIconStyle(placeLat, placeLon, placeName, placeDesc, iconHref, 1.0)
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.addPlaceIconStyle = function (placeLat, placeLon, placeName, placeDesc, iconHref, iconScale) {
|
||||
this.placemarksToAdd.push([placeLat, placeLon, placeName, placeDesc, iconHref, iconScale])
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.batchDraw = function (){
|
||||
|
||||
// placemarks
|
||||
for (var p in this.placemarksToAdd){
|
||||
this.makePlaceIconStyle2D(this.placemarksToAdd[p][0], this.placemarksToAdd[p][1], this.placemarksToAdd[p][2], this.placemarksToAdd[p][3], this.placemarksToAdd[p][4], this.placemarksToAdd[p][5])
|
||||
}
|
||||
|
||||
// lines
|
||||
for (var l in this.linesToAdd)
|
||||
{
|
||||
this.connect2D(this.linesToAdd[l][0], this.linesToAdd[l][1], this.linesToAdd[l][2], this.linesToAdd[l][3])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.makePlaceIconStyle2D = function makePlaceIconStyle(placeLat, placeLon, placeName, placeDesc, iconHref, iconScale) {
|
||||
|
||||
var icon = new GIcon(G_DEFAULT_ICON);
|
||||
// friendlier setup for maps
|
||||
if (iconHref == "http://maps.google.com/mapfiles/kml/paddle/red-circle.png")
|
||||
icon.image = "http://maps.gstatic.com/intl/en_us/mapfiles/marker.png"
|
||||
|
||||
|
||||
// Set up our GMarkerOptions object
|
||||
var markerOptions = { icon:icon };
|
||||
|
||||
|
||||
this.map.addOverlay(new google.maps.Marker(new google.maps.LatLng(placeLat, placeLon), markerOptions))
|
||||
}
|
||||
|
||||
|
||||
NetworkViewSkin2D.prototype.addConnect = function (start, stop, w, color){
|
||||
this.linesToAdd.push([start, stop, w, color])
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.connect2D = function (start, stop, w, color){
|
||||
var polyline = new GPolyline([
|
||||
new GLatLng(start.lat, start.lon),
|
||||
new GLatLng(stop.lat, stop.lon)
|
||||
], "#" + color, w);
|
||||
|
||||
this.map.addOverlay(polyline);
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.Destroy = function(){
|
||||
this.div = null
|
||||
this.baseWidget = null
|
||||
this.loadingDiv = null
|
||||
this.innerDiv = null
|
||||
this.selectbox = null
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.OnOutputTypeChange = function(){
|
||||
}
|
||||
|
||||
|
||||
NetworkViewSkin2D.prototype.QueryStarted = function(){
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.QueryError = function(error)
|
||||
{
|
||||
this.innerDiv.text("There was an error while making the AJAX call:" + error);
|
||||
// leave this.inQuery mode
|
||||
this.inQuery = false;
|
||||
//this.loadingDiv.css("display", "none");
|
||||
this.div.css("background-color", "white");
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.QuerySuccess = function(isInitial, response)
|
||||
{
|
||||
this.data = response
|
||||
|
||||
// make a record object that traverses easier
|
||||
this.data = this.CreateIndexedJSONRDF()
|
||||
|
||||
this.TryRender()
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.CreateIndexedJSONRDF = function()
|
||||
{
|
||||
|
||||
var indexedJSONRDF = {}
|
||||
|
||||
for (record in this.data['records'])
|
||||
{
|
||||
var subject = {}
|
||||
for(entityName in this.data['records'][record]['entityNames'])
|
||||
{
|
||||
indexedJSONRDF[this.data['records'][record]['entityNames'][entityName]] = subject
|
||||
}
|
||||
for(predicate in this.data['records'][record]['fieldValues'])
|
||||
{
|
||||
var statement = {}
|
||||
|
||||
var urisInPath = predicate.split(" ");
|
||||
subject[urisInPath[urisInPath.length - 1]] = statement;
|
||||
|
||||
statement.object = this.data['records'][record]['fieldValues'][predicate]
|
||||
|
||||
if (this.data['records'][record]['fieldValues'][predicate].objType == "uri")
|
||||
{
|
||||
// I have a hunch uriToTitle will break if object is an Array
|
||||
var uriLink = uriToTitle(statement.object)
|
||||
statement.objectlink = decodeURIComponent(uriLink).link(uriLink)
|
||||
}
|
||||
|
||||
statement.role = this.data['records'][record]['fieldValues'][predicate].role
|
||||
}
|
||||
}
|
||||
|
||||
return indexedJSONRDF
|
||||
}
|
||||
|
||||
NetworkViewSkin2D.prototype.TryRender = function(obj) {
|
||||
|
||||
if (this.map != "" && this.data != ""){
|
||||
// good ol' loop for unconnected segments graph traversal
|
||||
for (subject in this.data)
|
||||
{
|
||||
this.placeAndDraw(subject)
|
||||
}
|
||||
|
||||
// suspend rendering of globe while we draw
|
||||
this.batchDraw()
|
||||
this.map.setCenter(new GLatLng(this.lat, this.lon), 2);
|
||||
}
|
||||
}
|
||||
231
widget/js/TableViewCisternSkin.js
Normal file
231
widget/js/TableViewCisternSkin.js
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
// Constructor
|
||||
function TableViewCisternSkin(div, baseWidget, useInitialQuery){
|
||||
this.div = jQuery("#"+div)
|
||||
this.baseWidget = baseWidget
|
||||
this.useInitialQuery = useInitialQuery
|
||||
|
||||
this.loadingDiv = jQuery('<div><img src="'+wgScriptPath+'/extensions/AqueductExtension/widget/js/ajax-loader.gif" alt="Loading..." /></div>').css("display", "hidden")
|
||||
this.loadingDiv.css("position", "relative").css("float", "left").css("z-index", 1000)
|
||||
this.div.append(this.loadingDiv)
|
||||
|
||||
this.innerDiv = jQuery('<div></div>')
|
||||
this.div.append(this.innerDiv)
|
||||
|
||||
this.div.css('overflow', 'auto');
|
||||
|
||||
this.inQuery = false
|
||||
}
|
||||
|
||||
TableViewCisternSkin.prototype.Destroy = function(){
|
||||
this.div = null
|
||||
this.baseWidget = null
|
||||
this.loadingDiv = null
|
||||
this.innerDiv = null
|
||||
this.selectbox = null
|
||||
}
|
||||
|
||||
TableViewCisternSkin.prototype.OnOutputTypeChange = function(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
TableViewCisternSkin.prototype.QueryStarted = function(){
|
||||
var gridViewBounds = this.div
|
||||
var pnlPopupBounds = this.loadingDiv
|
||||
var x = Math.round(gridViewBounds.width() / 2) - Math.round(pnlPopupBounds.width() / 2);
|
||||
var y = Math.round(gridViewBounds.height() / 2) - Math.round(pnlPopupBounds.height() / 2);
|
||||
this.loadingDiv.css("top", y)
|
||||
this.loadingDiv.css("left", x)
|
||||
this.loadingDiv.css("display", "inline")
|
||||
this.loadingDiv.css("background-color", "white")
|
||||
this.div.css("background-color", "gray")
|
||||
this.inQuery = true
|
||||
}
|
||||
|
||||
TableViewCisternSkin.prototype.QueryError = function(error)
|
||||
{
|
||||
this.innerDiv.text("There was an error while making the AJAX call:" + error);
|
||||
// leave this.inQuery mode
|
||||
this.inQuery = false;
|
||||
this.loadingDiv.css("display", "none");
|
||||
this.div.css("background-color", "white");
|
||||
}
|
||||
|
||||
TableViewCisternSkin.prototype.QuerySuccess = function(isInitial, response)
|
||||
{
|
||||
this.innerDiv.text('TableViewCisternSkin')
|
||||
|
||||
this.baseWidget.ProfileWidget("Building HTML");
|
||||
var html = [];
|
||||
html.push("<table style='font-family:sans-serif;font-size:small;border:1px solid black;text-align:center;border-collapse:collapse;' class='tableviewcisterntable'>");
|
||||
|
||||
var linkElementPrefix = "<a href='" + wgServer + wgScript + "?title=";
|
||||
var linkElementPrefixForTd = "<td style='padding:0px 5px;border:1px solid black; background-color:#F4F4F4;border-collapse: collapse'>" + linkElementPrefix;
|
||||
|
||||
|
||||
html.push("<th style='padding:0px 5px;border:1px solid black; background-color:#F4F4F4;border-collapse: collapse'>entity</th>");
|
||||
|
||||
//Add the columns
|
||||
for (f in response['fields'])
|
||||
{
|
||||
html.push("<th style='padding:0px 5px;border:1px solid black; background-color:#F4F4F4;border-collapse: collapse'>");
|
||||
html.push(this.EncodeHTML(response['fields'][f].fieldName.toString()));
|
||||
html.push("</th>");
|
||||
}
|
||||
html.push("</tr>");
|
||||
|
||||
for (r in response['records'])
|
||||
{
|
||||
html.push("<tr style='z-index:1'>");
|
||||
// Note please, that all wiki titles returned by this function are now uriEncodeComponent()'d.
|
||||
var entityTitle = uriToTitle(response['records'][r]['entityNames'][0]);
|
||||
html.push(linkElementPrefixForTd);
|
||||
html.push(encodeURIComponent(entityTitle));
|
||||
html.push("'>");
|
||||
html.push(this.EncodeHTML(entityTitle));
|
||||
html.push("</a></td>");
|
||||
|
||||
for (f in response['fields'])
|
||||
{
|
||||
var fieldVal = response['records'][r]['fieldValues'][response['fields'][f].fullName];
|
||||
if (fieldVal)
|
||||
{
|
||||
var tdindex = html.length;
|
||||
html.push("<td style='padding:0px 5px;border:1px solid black;border-collapse: collapse;background-color:#F4F4F4'>");
|
||||
var longDataContainer = null;
|
||||
if (fieldVal.toString().length > 100)
|
||||
{
|
||||
longDataContainer = "<span style='font-size:smaller'><br/>(...click to expand...)</span><div id='data' style='display:none'>";
|
||||
}
|
||||
for (v in fieldVal)
|
||||
{
|
||||
// Check the data type to see if a link should be printed.
|
||||
if (fieldVal[v].objType == "uri")
|
||||
{
|
||||
// Note please, that all wiki titles returned by this function are now uriEncodeComponent()'d.
|
||||
var nText = uriToTitle(fieldVal[v].toString());
|
||||
var encodedText = this.EncodeHTML(nText);
|
||||
var n = linkElementPrefix + encodeURIComponent(nText)+"'>"+encodedText+"</a>";
|
||||
}
|
||||
else
|
||||
{
|
||||
var nText = fieldVal[v].toString();
|
||||
var encodedText = this.EncodeHTML(nText);
|
||||
var n = encodedText;
|
||||
}
|
||||
//Check if the cell contents will be too long for everything to fit
|
||||
if (!longDataContainer)
|
||||
{
|
||||
if (v > 0)
|
||||
{
|
||||
html.push(", ");
|
||||
}
|
||||
html.push(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v > 0)
|
||||
{
|
||||
html.push(", ");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Print the first 100 characters of the first object for this column
|
||||
html.push(encodedText.substr(0,100));
|
||||
}
|
||||
longDataContainer = longDataContainer + n;
|
||||
}
|
||||
}
|
||||
if (longDataContainer)
|
||||
{
|
||||
html.push(longDataContainer + "</div>");
|
||||
//Slip the long data event handler into the HTML
|
||||
html[tdindex] = "<td onclick='TableViewCisternSkin.prototype.DisplayHiddenData(this)' style='border:1px solid black; border-collapse: collapse; background-color:#F4F4F4'>";
|
||||
}
|
||||
html.push("</td>");
|
||||
}
|
||||
else
|
||||
{
|
||||
html.push("<td style='padding:0px 5px;border:1px solid black;border-collapse: collapse;background-color:#F4F4F4'> </td>");
|
||||
}
|
||||
}
|
||||
|
||||
html.push("</tr>");
|
||||
}
|
||||
html.push("</table>");
|
||||
|
||||
this.baseWidget.ProfileWidget("Setting HTML");
|
||||
this.innerDiv.html(html.join(""));
|
||||
|
||||
this.baseWidget.ProfileWidget("Finishing up");
|
||||
// leave this.inQuery mode
|
||||
this.inQuery = false
|
||||
|
||||
this.loadingDiv.css("display", "none")
|
||||
this.div.css("background-color", "white")
|
||||
}
|
||||
|
||||
TableViewCisternSkin.prototype.DisplayHiddenData = function (obj)
|
||||
{
|
||||
var expandedDiv = jQuery("<div id='expanded'></div>")
|
||||
var width = 300 + Math.round(jQuery(obj).children("#data").text().length / 1000.0) * 100
|
||||
|
||||
expandedDiv.text(jQuery(obj).children("#data").text())
|
||||
expandedDiv.css("position", "absolute").css("float", "left").css("z-index", 1000).css("width", width).click(TableViewCisternSkin.prototype.RemoveHiddenData)
|
||||
expandedDiv.css("display", "inline")
|
||||
|
||||
|
||||
// td - tr - tbody - table - div
|
||||
jQuery(obj).parent().parent().parent().parent().append(expandedDiv)
|
||||
|
||||
|
||||
var myHeight = jQuery(obj).offset().top
|
||||
|
||||
expandedDiv.css("top", myHeight)
|
||||
|
||||
// we need to set ourselves lower then the rows above us here
|
||||
|
||||
var gridViewBounds = jQuery(obj)
|
||||
var x = (gridViewBounds.position().left + Math.round(gridViewBounds.innerWidth() / 2)) - Math.round(expandedDiv.width() / 2);
|
||||
var y = gridViewBounds.offset().top
|
||||
//expandedDiv.css("top", y)
|
||||
expandedDiv.css("left", x)
|
||||
expandedDiv.css("background-color", "#FFFFCC")
|
||||
}
|
||||
|
||||
TableViewCisternSkin.prototype.RemoveHiddenData = function ()
|
||||
{
|
||||
jQuery(this).remove()
|
||||
}
|
||||
|
||||
TableViewCisternSkin.prototype.EncodeHTML = function (s)
|
||||
{
|
||||
//We do not encode "unicode" characters, but the browser built-in HTML encoders don't
|
||||
//encode unicode characters either.
|
||||
//Some other things (like spaces and tabs) will not be encoded perfectly
|
||||
var a = s.replace("\r\n","<br/>");
|
||||
a = a.replace("\r","<br/>");
|
||||
a = a.replace("\n","<br/>");
|
||||
a = a.replace("&","&");
|
||||
a = a.replace("<","<");
|
||||
a = a.replace(">",">");
|
||||
return a;
|
||||
}
|
||||
138
widget/js/TemplateCisternSkin.js
Normal file
138
widget/js/TemplateCisternSkin.js
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
Aqueduct: A linked data semantic web extension for MediaWiki
|
||||
Copyright (C) 2010 The Johns Hopkins University/Applied Physics Laboratory
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
// Constructor
|
||||
function LayoutSkin(div, baseWidget, useInitialQuery){
|
||||
this.data = ""
|
||||
|
||||
this.div = jQuery("#"+div)
|
||||
this.baseWidget = baseWidget
|
||||
this.useInitialQuery = useInitialQuery
|
||||
|
||||
this.loadingDiv = jQuery('<div><img src="'+wgScriptPath+'/extensions/AqueductExtension/widget/js/ajax-loader.gif" alt="Loading..." /></div>').css("display", "none")
|
||||
this.loadingDiv.css("position", "relative").css("float", "left").css("z-index", 1000)
|
||||
this.div.append(this.loadingDiv)
|
||||
|
||||
this.innerDiv = jQuery('<div id="' + baseWidget.divName + '_innerdiv"></div>')
|
||||
|
||||
this.div.append(this.innerDiv)
|
||||
|
||||
this.inQuery = false
|
||||
}
|
||||
|
||||
LayoutSkin.prototype.Destroy = function(){
|
||||
this.div = null
|
||||
this.baseWidget = null
|
||||
this.loadingDiv = null
|
||||
this.innerDiv = null
|
||||
this.selectbox = null
|
||||
}
|
||||
|
||||
LayoutSkin.prototype.OnOutputTypeChange = function(){
|
||||
}
|
||||
|
||||
|
||||
LayoutSkin.prototype.QueryStarted = function(){
|
||||
var gridViewBounds = this.div
|
||||
var pnlPopupBounds = this.loadingDiv
|
||||
var x = /*gridViewBounds.offset().left +*/ Math.round(gridViewBounds.width() / 2) - Math.round(pnlPopupBounds.width() / 2);
|
||||
var y = /*gridViewBounds.offset().top +*/ Math.round(gridViewBounds.height() / 2) - Math.round(pnlPopupBounds.height() / 2);
|
||||
this.loadingDiv.css("top", y)
|
||||
this.loadingDiv.css("left", x)
|
||||
this.loadingDiv.css("display", "inline")
|
||||
this.loadingDiv.css("background-color", "white")
|
||||
this.div.css("background-color", "gray")
|
||||
}
|
||||
|
||||
LayoutSkin.prototype.QueryError = function(error)
|
||||
{
|
||||
this.innerDiv.text("There was an error while making the AJAX call:" + error);
|
||||
// leave this.inQuery mode
|
||||
this.inQuery = false;
|
||||
this.div.css("background-color", "white");
|
||||
}
|
||||
|
||||
LayoutSkin.prototype.QuerySuccess = function(isInitial, response)
|
||||
{
|
||||
this.data = response;
|
||||
this.data = this.CreateIndexedJSONRDF();
|
||||
|
||||
// attach the template
|
||||
this.div.setTemplate(this.baseWidget.layout);
|
||||
|
||||
// process the template
|
||||
this.div.processTemplate(this.data);
|
||||
|
||||
this.loadingDiv.css("display", "none")
|
||||
this.div.css("background-color", "white")
|
||||
}
|
||||
|
||||
LayoutSkin.prototype.CreateIndexedJSONRDF = function()
|
||||
{
|
||||
var indexedJSONRDF = {}
|
||||
var linkElementPrefix = wgServer + wgScript + "?title=";
|
||||
for (record in this.data['records'])
|
||||
{
|
||||
var subject = {}
|
||||
for(entityName in this.data['records'][record]['entityNames'])
|
||||
{
|
||||
indexedJSONRDF[this.data['records'][record]['entityNames'][entityName]] = subject
|
||||
}
|
||||
for(predicate in this.data['records'][record]['fieldValues'])
|
||||
{
|
||||
var fieldVal = this.data['records'][record]['fieldValues'][predicate];
|
||||
var valuearray = {'value':'','link':'','role':''};
|
||||
valuearray['all'] = new Array();
|
||||
for (v in fieldVal)
|
||||
{
|
||||
if (valuearray.value.length>0)
|
||||
{
|
||||
valuearray.value = valuearray.value + ",";
|
||||
valuearray.link = valuearray.link + ",";
|
||||
valuearray.role = valuearray.role + ",";
|
||||
}
|
||||
var valueelement = {'role':fieldVal[v].role};
|
||||
// Check the data type to see if a link should be printed.
|
||||
if (fieldVal[v].objType == "uri")
|
||||
{
|
||||
// Note please, that all wiki titles returned by this function are now uriEncodeComponent()'d.
|
||||
var nText = uriToTitle(fieldVal[v].toString());
|
||||
valueelement.value = nText;
|
||||
valueelement.link = linkElementPrefix + encodeURIComponent(nText);
|
||||
}
|
||||
else
|
||||
{
|
||||
valueelement.value = fieldVal[v].toString();
|
||||
valueelement.link = '#';
|
||||
}
|
||||
|
||||
valuearray.value = valuearray.value + valueelement.value;
|
||||
valuearray.link = valuearray.link + valueelement.link;
|
||||
valuearray.role = valuearray.role + valueelement.role;
|
||||
valuearray.all.push(valueelement);
|
||||
}
|
||||
var urisInPath = predicate.split(" ");
|
||||
subject[urisInPath[urisInPath.length - 1]] = valuearray;
|
||||
}
|
||||
var myvalue = uriToTitle(this.data['records'][record]['entityNames'][0]);
|
||||
subject['myvalue'] = myvalue;
|
||||
subject['mylink'] = linkElementPrefix + encodeURIComponent(myvalue);
|
||||
}
|
||||
return indexedJSONRDF
|
||||
}
|
||||
|
||||
BIN
widget/js/ajax-loader.gif
Normal file
BIN
widget/js/ajax-loader.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
29
widget/js/aqueduct-layout.css
Normal file
29
widget/js/aqueduct-layout.css
Normal file
@@ -0,0 +1,29 @@
|
||||
.ui-layout-pane { /* all 'panes' */
|
||||
background: #FFF;
|
||||
border: 1px solid #BBB;
|
||||
padding: 10px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.ui-layout-content {
|
||||
padding: 10px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
.ui-layout-resizer { /* all 'resizer-bars' */
|
||||
background: #DDD;
|
||||
}
|
||||
|
||||
.ui-layout-toggler { /* all 'toggler-buttons' */
|
||||
background: #AAA;
|
||||
}
|
||||
#gridContainer{
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.pane {
|
||||
/*display: none;*/
|
||||
/* will appear when layout inits */
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user