]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/SemanticWeb.php
use And by default; cleanup
[SourceForge/phpwiki.git] / lib / SemanticWeb.php
1 <?php
2 /**
3  * What to do on ?format=rdf  What to do on ?format=owl
4  *
5  * Map relations on a wikipage to a RDF ressource to build a "Semantic Web"
6  * - a web ontology frontend compatible to OWL (web ontology language).
7  * http://www.w3.org/2001/sw/Activity
8  * Simple RDF ontologies contain facts and rules, expressed by RDF triples:
9  *   Subject (page) -> Predicate (verb, relation) -> Object (links)
10  * OWL extents that to represent a typical OO framework.
11  *  OO predicates:
12  *    is_a, has_a, ...
13  *  OWL predicates:
14  *    subClassOf, restrictedBy, onProperty, intersectionOf, allValuesFrom, ...
15  *    someValuesFrom, unionOf, equivalentClass, disjointWith, ...
16  *    plus the custom vocabulary (ontology): canRun, canBite, smellsGood, ...
17  *  OWL Subjects: Class, Restriction, ...
18  *  OWL Properties: type, label, comment, ...
19  * DAML should also be supported.
20  *
21  * Purpose:
22  * - Another way to represent various KB models in various DL languages.
23  *   (OWL/DAML/other DL)
24  * - Frontend to various KB model reasoners and representations.
25  * - Generation/update of static wiki pages based on external OWL/DL/KB
26  *   (=> ModelTest/Categories)
27  *   KB Blackboard and Visualization.
28  * - OWL generation based on static wiki pages (ModelTest?format=owl)
29  *
30  * Facts: (may be represented by special links on a page)
31  *  - Each page must be representable with an unique URL.
32  *  - Each fact must be representable with an unique RDF triple.
33  *  - A class is represented by a category page.
34  *  - To represent more expressive description logic, "enriched"
35  *    links will not be enough (? variable symbolic objects).
36  *
37  * Rules: (may be represented by special content on a page)
38  *  - Syntax: reasoner backend specific, or common or ?
39  *
40  * RDF Triple: (representing facts)
41  *   Subject (page) -> Predicate (verb, relation) -> Object (links)
42  * Subject: a page
43  * Verb:
44  *   Special link qualifiers represent RDF triples, based on RDF standard notation.
45  *   See RDF standard DTD's on daml.org and w3.org, plus your custom predicates.
46  *   (need your own DTD)
47  *   Example: page [Ape] isa:Animal, ...
48  * Object: special links on a page.
49  * Class: WikiCategory
50  * Model: Basepage for a KB. (parametrizeable pages or copies of modified snapshots?)
51  *
52  * DL: Description Logic
53  * KB: Knowledge Base
54  *
55  * Discussion:
56  * Of course *real* expert systems ("reasoners") will help/must be used in
57  * optimization and maintainance of the SemanticWeb KB (Knowledge
58  * Base). Hooks will be tested to KM (an interactive KB playground),
59  * LISA (standard unifier), FaCT, RACER, ...
60  * Maybe also ZEBU (parser generator) is needed to convert the wiki KB
61  * syntax to the KB reasoner backend (LISA, KM, CLIPS, JESS, FaCT,
62  * ...) and forth.
63  * pOWL is a simple php backend with some very simple AI logic in PHP,
64  * though I strongly doubt the usefulness of reasoners not written in
65  * Common Lisp.
66  *
67  * SEAL (omntoweb.org) is similar to that, just on top of the Zope CMF.
68  * FaCT uses e.g. this KB DTD:
69 <!ELEMENT KNOWLEDGEBASE (DEFCONCEPT|DEFROLE|IMPLIESC|EQUALC|IMPLIESR|EQUALR|TRANSITIVE|FUNCTIONAL)*>
70 <!ELEMENT CONCEPT (PRIMITIVE|TOP|BOTTOM|AND|OR|NOT|SOME|ALL|ATMOST|ATLEAST)>
71 <!ELEMENT ROLE (PRIMROLE|INVROLE)>
72 ... (facts and rules described in XML)
73  *
74  * Links:
75  *   http://phpwiki.org/SemanticWeb,
76  *   http://en.wikipedia.org/wiki/Knowledge_representation
77  *   http://www.ontoweb.org/
78  *   http://www.semwebcentral.org/ (OWL on top of FusionForge)
79  *
80  *
81  * Author: Reini Urban <rurban@x-ray.at>
82  */
83 /*============================================================================*/
84 /*
85  * Copyright 2004,2007 Reini Urban
86  *
87  * This file is part of PhpWiki.
88  *
89  * PhpWiki is free software; you can redistribute it and/or modify
90  * it under the terms of the GNU General Public License as published by
91  * the Free Software Foundation; either version 2 of the License, or
92  * (at your option) any later version.
93  *
94  * PhpWiki is distributed in the hope that it will be useful,
95  * but WITHOUT ANY WARRANTY; without even the implied warranty of
96  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
97  * GNU General Public License for more details.
98  *
99  * You should have received a copy of the GNU General Public License along
100  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
101  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
102  */
103
104 require_once 'lib/RssWriter.php';
105 require_once 'lib/TextSearchQuery.php';
106 require_once 'lib/Units.php';
107
108 /**
109  * RdfWriter - A class to represent the links of a list of wikipages as RDF.
110  * Supports ?format=rdf
111  *
112  * RdfWriter (unsorted)
113  *  - RssWriter (timesorted)
114  *    - RecentChanges (?action=RecentChanges&format=rdf) (filtered)
115  */
116 class RdfWriter extends RssWriter // in fact it should be rewritten to be other way round.
117 {
118     function RdfWriter(&$request, &$pagelist)
119     {
120         $this->_request =& $request;
121         $this->_pagelist =& $pagelist;
122         $this->XmlElement('rdf:RDF',
123             array('xmlns' => "http://purl.org/rss/1.0/",
124                 'xmlns:rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'));
125
126         $this->_modules = array(
127             //Standards
128             'content' => "http://purl.org/rss/1.0/modules/content/",
129             'dc' => "http://purl.org/dc/elements/1.1/",
130         );
131
132         $this->_uris_seen = array();
133         $this->_items = array();
134
135         $this->wiki_xmlns_xml = WikiURL(_("UriResolver") . "?", false, true);
136         $this->wiki_xmlns_url = PHPWIKI_BASE_URL;
137
138         $this->pre_ns_buffer =
139             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" .
140                 "<!DOCTYPE rdf:RDF[\n" .
141                 "\t" . "<!ENTITY rdf 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n" .
142                 "\t" . "<!ENTITY rdfs 'http://www.w3.org/2000/01/rdf-schema#'>\n" .
143                 "\t" . "<!ENTITY owl 'http://www.w3.org/2002/07/owl#'>\n" .
144                 "\t" . "<!ENTITY smw 'http://smw.ontoware.org/2005/smw#'>\n" .
145                 "\t" . "<!ENTITY smwdt 'http://smw.ontoware.org/2005/smw-datatype#'>\n" .
146                 // A note on "wiki": this namespace is crucial as a fallback when it would be illegal to start e.g. with a number. In this case, one can always use wiki:... followed by "_" and possibly some namespace, since _ is legal as a first character.
147                 "\t" . "<!ENTITY wiki '" . $this->wiki_xmlns_xml . "'>\n" .
148                 "\t" . "<!ENTITY relation '" . $this->wiki_xmlns_xml .
149                 $this->makeXMLExportId(urlencode(str_replace(' ', '_', _("Relation") . ':'))) . "'>\n" .
150                 "\t" . "<!ENTITY attribute '" . $this->wiki_xmlns_xml .
151                 $this->makeXMLExportId(urlencode(str_replace(' ', '_', _("Attribute") . ':'))) . "'>\n" .
152                 "\t" . "<!ENTITY wikiurl '" . $this->wiki_xmlns_url . "'>\n" .
153                 "]>\n\n" .
154                 "<rdf:RDF\n" .
155                 "\t" . "xmlns:rdf=\"&rdf;\"\n" .
156                 "\t" . "xmlns:rdfs=\"&rdfs;\"\n" .
157                 "\t" . "xmlns:owl =\"&owl;\"\n" .
158                 "\t" . "xmlns:smw=\"&smw;\"\n" .
159                 "\t" . "xmlns:wiki=\"&wiki;\"\n" .
160                 "\t" . "xmlns:relation=\"&relation;\"\n" .
161                 "\t" . "xmlns:attribute=\"&attribute;\"";
162         $this->post_ns_buffer =
163             "\n\t<!-- reference to the Semantic MediaWiki schema -->\n" .
164                 "\t" . "<owl:AnnotationProperty rdf:about=\"&smw;hasArticle\">\n" .
165                 "\t\t" . "<rdfs:isDefinedBy rdf:resource=\"http://smw.ontoware.org/2005/smw\"/>\n" .
166                 "\t" . "</owl:AnnotationProperty>\n" .
167                 "\t" . "<owl:AnnotationProperty rdf:about=\"&smw;hasType\">\n" .
168                 "\t\t" . "<rdfs:isDefinedBy rdf:resource=\"http://smw.ontoware.org/2005/smw\"/>\n" .
169                 "\t" . "</owl:AnnotationProperty>\n" .
170                 "\t" . "<owl:Class rdf:about=\"&smw;Thing\">\n" .
171                 "\t\t" . "<rdfs:isDefinedBy rdf:resource=\"http://smw.ontoware.org/2005/smw\"/>\n" .
172                 "\t" . "</owl:Class>\n" .
173                 "\t<!-- exported page data -->\n";
174     }
175
176     function format()
177     {
178         header("Content-type: application/rdf+xml; charset=UTF-8");
179         echo $this->pre_ns_buffer;
180         echo ">\n";
181
182         $first = true;
183         $dbi = $this->_request->_dbi;
184         /* Elements per page:
185            out-links internal, out-links external
186            backlinks
187            relations
188            attributes
189         */
190         foreach ($this->_pagelist->_pages as $page) {
191             $relation = new TextSearchQuery("*");
192             foreach (array('linkto', 'linkfrom', 'relation', 'attribute') as $linktype) {
193                 $linkiter = $dbi->linkSearch($pages, $search, $linktype, $relation);
194             }
195             while ($link = $linkiter->next()) {
196                 if (mayAccessPage('view', $rev->_pagename)) {
197                     $linkto->addItem($this->item_properties($rev),
198                         $this->pageURI($rev));
199                     if ($first)
200                         $this->setValidators($rev);
201                     $first = false;
202                 }
203             }
204         }
205
206         echo $this->post_ns_buffer;
207         echo "</rdf:RDF>\n";
208     }
209
210     /** This function transforms a valid url-encoded URI into a string
211      *  that can be used as an XML-ID. The mapping should be injective.
212      */
213     function makeXMLExportId($uri)
214     {
215         $uri = str_replace('-', '-2D', $uri);
216         //$uri = str_replace( ':', '-3A', $uri); //already done by PHP
217         //$uri = str_replace( '_', '-5F', $uri); //not necessary
218         $uri = str_replace(array('"', '#', '&', "'", '+', '=', '%'),
219             array('-22', '-23', '-26', '-27', '-2B', '-3D', '-'),
220             $uri);
221         return $uri;
222     }
223
224     /** This function transforms an XML-ID string into a valid
225      *  url-encoded URI. This is the inverse to makeXMLExportID.
226      */
227     function makeURIfromXMLExportId($id)
228     {
229         $id = str_replace(array('-22', '-23', '-26', '-27', '-2B', '-3D', '-'),
230             array('"', '#', '&', "'", '+', '=', '%'),
231             $id);
232         $id = str_replace('-2D', '-', $id);
233         return $id;
234     }
235 }
236
237 /**
238  */
239 class RdfsWriter extends RdfWriter
240 {
241 }
242
243 /**
244  * OwlWriter - A class to represent a set of wiki pages (a DL model) as OWL.
245  * Requires an actionpage returning a pagelist.
246  * Supports ?format=owl
247  *
248  * OwlWriter
249  *  - RdfWriter
250  *  - Reasoner
251  */
252 class OwlWriter extends RdfWriter
253 {
254 }
255
256 /**
257  * ModelWriter - Export a KB as set of wiki pages.
258  * Requires an actionpage returning a pagelist.
259  * Probably based on some convenient DL expression syntax. (deffact, defrule, ...)
260  *
261  * ModelWriter
262  *  - OwlWriter
263  *  - ReasonerBackend
264  */
265 class ModelWriter extends OwlWriter
266 {
267 }
268
269 /**
270  *  NumericSearchQuery can do:
271  *         ("population < 20000 and area > 1000000", array("population", "area"))
272  *  ->match(array('population' => 100000, 'area' => 10000000))
273  * @see NumericSearchQuery
274  *
275  *  SemanticAttributeSearchQuery can detect and unify units in numbers.
276  *         ("population < 2million and area > 100km2", array("population", "area"))
277  *  ->match(array('population' => 100000, 'area' => 10000000))
278  *
279  * Do we need a real parser or can we just regexp over some allowed unit
280  * suffixes to detect the numbers?
281  * See man units(1) and /usr/share/units.dat
282  * base units: $ units "1 million miles"
283  *                     Definition: 1.609344e+09 m
284  */
285 class SemanticAttributeSearchQuery
286     extends NumericSearchQuery
287 {
288     /*
289     public $base_units = array('m'   => explode(',','km,miles,cm,dm,mm,ft,inch,inches,meter'),
290                 'm^2' => explode(',','km^2,ha,cm^2,mi^2'),
291                 'm^3' => explode(',','km^3,lit,cm^3,dm^3,gallons'),
292                 );
293     */
294
295     /**
296      * We need to detect units from the freetext query:
297      * population > 1 million
298      */
299     function SemanticAttributeSearchQuery($search_query, $placeholders, $unit = '')
300     {
301         $this->NumericSearchQuery($search_query, $placeholders);
302         $this->_units = new Units();
303         $this->unit = $unit;
304     }
305
306     /**
307      * Strip non-numeric chars from the variable (as the groupseperator) and replace
308      * it in the symbolic query for evaluation.
309      * This version unifies the attribute values from the database to a
310      * numeric basevalue before comparison. (area:=963.6km^2 => 9.366e+08 m^2)
311      *
312      * @access private
313      * @param $value number   A numerical value: integer, float or string.
314      * @param $x string       The variable name to be replaced in the query.
315      * @return string
316      */
317     function _bind($value, $x)
318     {
319         $ori_value = $value;
320         $value = preg_replace("/,/", "", $value);
321         $this->bound[] = array('linkname' => $x,
322             'linkvalue' => $value);
323         // We must ensure that the same baseunits are matched against.
324         // We cannot compare m^2 to m or ''
325         $val_base = $this->_units->basevalue($value);
326         if (!DISABLE_UNITS and $this->_units->baseunit($value) != $this->unit) {
327             // Poor user has selected an attribute, but no unit. assume he means the baseunit
328             if (count($this->getVars() == 1) and $this->unit == '') {
329                 ;
330             } else {
331                 // non-matching units are silently ignored
332                 $this->workquery = '';
333                 return '';
334             }
335         }
336         $value = $val_base;
337         if (!is_numeric($value)) {
338             $this->workquery = ''; //must return false
339             trigger_error("Cannot match against non-numeric attribute value $x := $ori_value",
340                 E_USER_NOTICE);
341             return '';
342         }
343
344         $this->workquery = preg_replace("/\b" . preg_quote($x, "/") . "\b/", $value, $this->workquery);
345         return $this->workquery;
346     }
347
348 }
349
350 /**
351  *  SemanticSearchQuery can do:
352  *     (is_a::city and population < 20000) and (*::city and area > 1000000)
353  *  ->match(array('is_a' => 'city', 'linkfrom' => array(),
354  *          population' => 100000, 'area' => 10000000))
355  * @return array  A list of found and bound matches
356  */
357 class SemanticSearchQuery
358     extends SemanticAttributeSearchQuery
359 {
360     function hasAttributes()
361     { // TODO
362     }
363
364     function hasRelations()
365     { // TODO
366     }
367
368     function getLinkNames()
369     { // TODO
370     }
371 }
372
373 /**
374  * ReasonerBackend - hooks to reasoner backends.
375  * via http as with DIG,
376  * or internally
377  */
378 class ReasonerBackend
379 {
380     function ReasonerBackend()
381     {
382         ;
383     }
384
385     /**
386      * transform to reasoner syntax
387      */
388     function transformTo()
389     {
390         ;
391     }
392
393     /**
394      * transform from reasoner syntax
395      */
396     function transformFrom()
397     {
398         ;
399     }
400
401     /**
402      * call the reasoner
403      */
404     function invoke()
405     {
406         ;
407     }
408 }
409
410 class ReasonerBackend_LISA extends ReasonerBackend
411 {
412 }
413
414 class ReasonerBackend_Racer extends ReasonerBackend
415 {
416 }
417
418 class ReasonerBackend_KM extends ReasonerBackend
419 {
420 }
421
422 // Local Variables:
423 // mode: php
424 // tab-width: 8
425 // c-basic-offset: 4
426 // c-hanging-comment-ender-p: nil
427 // indent-tabs-mode: nil
428 // End: