PageRenderTime 66ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/rdfapi-php/api/syntax/N3Serializer.php

https://github.com/koja13/DSi2.0
PHP | 526 lines | 304 code | 87 blank | 135 comment | 78 complexity | 2b85627759d05ce1a04e9c2d19144939 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. // ----------------------------------------------------------------------------------
  3. // Class: N3Serializer
  4. // ----------------------------------------------------------------------------------
  5. /**
  6. * PHP Notation3 Serializer
  7. *
  8. * This class serialises models to N3 Syntax.
  9. *
  10. * Supported N3 features:
  11. * <ul>
  12. * <li>Using [ ] for blank nodes, or _: if necessary</li>
  13. * <li>Literal datatype- and xmlLanguageTag support</li>
  14. * </ul>
  15. *
  16. * Un-supported N3 Features include:
  17. * <ul>
  18. * <li>Reification</li>
  19. * </ul>
  20. *
  21. *
  22. * @author Gunnar AA. Grimnes <ggrimnes@csd.abdn.ac.uk>
  23. * @author Daniel Westphal <mail@d-westphal.de>
  24. * @author Christian Weiske <cweiske@cweiske.de>
  25. * @version $Id: N3Serializer.php 556 2008-01-22 10:52:48Z fusel2k $
  26. * @package syntax
  27. * @access public
  28. **/
  29. define('MAGIC_STRING', '~~~');
  30. class N3Serializer extends Object
  31. {
  32. var $debug = false;
  33. var $prefixes = array();
  34. var $noPrefixes = array();
  35. var $done; // keeps track of already serialized resources
  36. var $resourcetext;
  37. var $resourcetext_taken;
  38. var $model;
  39. var $res;
  40. var $anon;
  41. var $styleCompress = false;
  42. var $stylePretty = false;
  43. var $styleNest = false;
  44. /**
  45. * Constructor
  46. *
  47. * @access public
  48. */
  49. function N3Serializer()
  50. {
  51. $this->debug = false;
  52. }
  53. /**
  54. * Adds a new namespace prefix to use.
  55. * Unknown namespaces will become ns0, ns1 etc.
  56. * @access public
  57. * @param string $s
  58. * @returns void
  59. **/
  60. function addNSPrefix($ns, $prefix)
  61. {
  62. $this->prefixes[$ns] = $prefix;
  63. }
  64. /**
  65. * Clears all previously set namespace prefixes
  66. */
  67. function clearNSPrefixes()
  68. {
  69. $this->prefixes = array();
  70. }
  71. /**
  72. * Add a namespace that shall not get shortened by using a prefix.
  73. *
  74. * @param string $ns Namespace URI like "http://example.com/"
  75. */
  76. function addNoNSPrefix($ns)
  77. {
  78. $this->noPrefixes[$ns] = true;
  79. }
  80. /**
  81. * Clears all previously set noNamespace prefixes
  82. */
  83. function clearNoNSPrefixes()
  84. {
  85. $this->noPrefixes = array();
  86. }
  87. /**
  88. * Serializes a model to N3 syntax.
  89. *
  90. * @param object Model $model
  91. * @return string
  92. * @access public
  93. */
  94. function &serialize(&$m)
  95. {
  96. if (is_a($m, 'DbModel')) {
  97. $m=$m->getMemModel();
  98. }
  99. $this->reset();
  100. $this->model = $m;
  101. $this->res = "";
  102. // copy default namespaces
  103. global $default_prefixes;
  104. foreach($default_prefixes as $prefix => $namespace) {
  105. $this->addNSPrefix($namespace,$prefix);
  106. }
  107. $nps= $this->model->getParsedNamespaces();
  108. if ($nps!=false) {
  109. foreach ($nps as $uri => $prefix){
  110. $this->addNSPrefix($uri,$prefix);
  111. }
  112. }
  113. $namespaces = array();
  114. $count = array();
  115. $resources = array();
  116. foreach ($this->model->triples as $t) {
  117. $s = $t->getSubject();
  118. if (is_a($s, 'Resource')) {
  119. $namespaces[$s->getNamespace()] = 1;
  120. }
  121. $p = $t->getPredicate();
  122. if (is_a($p, 'Resource')) {
  123. $namespaces[$p->getNamespace()] = 1;
  124. }
  125. $o = $t->getObject();
  126. if (is_a($o, 'Resource')) {
  127. $namespaces[$o->getNamespace()] = 1;
  128. }
  129. $uri = $s->getURI();
  130. if (isset($count[$uri])) {
  131. $count[$uri]++;
  132. } else {
  133. $count[$uri] = 0;
  134. $resources[$uri] = $s;
  135. }
  136. if ($this->styleNest && is_a($s, 'BlankNode')) {
  137. //make sure blank nodes are sorted *after* normal nodes
  138. //so that they can be included
  139. $count[$uri] -= 0.00001;
  140. }
  141. }
  142. if (!HIDE_ADVERTISE) {
  143. $this->res .= '# Generated by N3Serializer.php from RDF RAP.'.LINEFEED
  144. .'# http://www.wiwiss.fu-berlin.de/suhl/bizer/rdfapi/index.html'
  145. .LINEFEED.LINEFEED;
  146. }
  147. $this->doNamespaces($namespaces);
  148. $this->res .= LINEFEED.LINEFEED;
  149. arsort($count);
  150. foreach ( $count as $k => $v) {
  151. $this->doResource($resources[$k]);
  152. // $this->res.=" .\n";
  153. }
  154. //make all replacements
  155. do {
  156. $bReplacements = false;
  157. foreach ($this->resourcetext as $r => $t) {
  158. if (preg_match_all('/'.MAGIC_STRING.'([^ ]+)'.MAGIC_STRING.'/', $t, $ms, PREG_SET_ORDER)) {
  159. foreach ($ms as $mseach) {
  160. $rp = $this->resourcetext[$mseach[1]];
  161. $this->resourcetext[$r] = preg_replace('/'.MAGIC_STRING.$mseach[1].MAGIC_STRING.'/', $rp, $t);
  162. $bReplacements = true;
  163. }
  164. }
  165. }
  166. } while ($bReplacements);
  167. //after all replacements took place, put the lines out
  168. $c = 0;
  169. foreach ($this->resourcetext as $r => $t) {
  170. if ($this->debug) {
  171. $this->res .= $c . ': ';
  172. }
  173. if (!(isset($this->resourcetext_taken[$r]) && $this->resourcetext_taken[$r]>0)) {
  174. $this->res .= $t . ' .' . LINEFEED;
  175. if ($this->stylePretty) {
  176. $this->res .= LINEFEED;
  177. }
  178. } else if ($this->debug ) {
  179. $this->res.=' Skipping : '.$t.LINEFEED;
  180. }
  181. $c++;
  182. }
  183. // $max=-1111;
  184. // $maxkey="";
  185. // foreach ($count as $k=>$c) {
  186. // if ( $c>$max) { $maxkey=$k; $max=$c; }
  187. // }
  188. // if ($this->debug) {
  189. // print "$maxkey is subject of most triples! ($max) \n";
  190. // }
  191. return $this->res;
  192. }//function &serialize(&$m)
  193. /**
  194. * Serializes a model and saves it into a file.
  195. * Returns FALSE if the model couldn't be saved to the file.
  196. *
  197. * @param object MemModel $model
  198. * @param string $filename
  199. * @return boolean
  200. * @access public
  201. */
  202. function saveAs(&$model, $filename)
  203. {
  204. // serialize model
  205. $n3 = $this->serialize($model);
  206. // write serialized model to file
  207. $file_handle = @fopen($filename, 'w');
  208. if ($file_handle) {
  209. fwrite($file_handle, $n3);
  210. fclose($file_handle);
  211. return true;
  212. } else {
  213. return false;
  214. };
  215. }
  216. /**
  217. * Set to true, if the N3 serializer should try to compress the blank node
  218. * syntax using [] whereever possible.
  219. */
  220. function setCompress($compress)
  221. {
  222. $this->styleCompress = $compress;
  223. }
  224. /**
  225. * Enables pretty printing in semicolon delimited sentences.
  226. */
  227. function setPrettyPrint($prettyPrint)
  228. {
  229. $this->stylePretty = $prettyPrint;
  230. }
  231. /**
  232. * Enables nesting of blank nodes with [] if
  233. * compression is activated via @see setCompress
  234. */
  235. function setNest($nest)
  236. {
  237. $this->styleNest = $nest;
  238. }
  239. /* ==================== Private Methods from here ==================== */
  240. /**
  241. * Readies this object for serializing another model
  242. * @access private
  243. * @param void
  244. * @returns void
  245. **/
  246. function reset()
  247. {
  248. $this->anon = 0;
  249. $this->done = array();
  250. $this->resourcetext_taken = array();
  251. $this->resourcetext = array();
  252. $this->res = '';
  253. $this->model = null;
  254. }
  255. /**
  256. * Makes ns0, ns1 etc. prefixes for unknown prefixes.
  257. * Outputs @prefix lines.
  258. * @access private
  259. * @param array $n
  260. * @returns void
  261. **/
  262. function doNamespaces(&$n)
  263. {
  264. $c = 0;
  265. foreach ($n as $ns => $nonsense) {
  266. if (!$ns || isset($this->noPrefixes[$ns])) {
  267. continue;
  268. }
  269. if (isset($this->prefixes[$ns])) {
  270. $p = $this->prefixes[$ns];
  271. } else {
  272. $p = 'ns' . $c;
  273. $this->prefixes[$ns] = $p;
  274. $c++;
  275. }
  276. $this->res .= "@prefix $p: <".$ns.'> .'.LINEFEED;
  277. }
  278. }
  279. /**
  280. * Fill in $resourcetext for a single resource.
  281. * Will recurse into Objects of triples, but should never look ? (really?)
  282. * @param object Resource $r
  283. * @returns boolean
  284. * @access private
  285. **/
  286. function doResource(&$r, $bEmbedded = false, $strIndent = ' ')
  287. {
  288. //var_dump($r->getURI());
  289. $ts = $this->model->find($r, null, null);
  290. if (count($ts->triples) == 0) {
  291. if ($bEmbedded) {
  292. $this->resourcetext[$r->getURI()] = '_:' . $r->getLabel();
  293. }
  294. return;
  295. }
  296. $out = '';
  297. if (isset($this->done[$r->getURI()]) && $this->done[$r->getURI()]) {
  298. if (!$this->styleNest && is_a($r, 'BlankNode')) {
  299. if ($this->resourcetext_taken[$r->getURI()] == 1) {
  300. //Oh bother, we must use the _:blah construct.
  301. $a = $this->resourcetext[$r->getURI()];
  302. $this->resourcetext[$r->getURI()]='_:anon'.$this->anon;
  303. $this->resourcetext['_:anon'.$this->anon]=$this->fixAnon($a, '_:anon'.$this->anon);
  304. $this->resourcetext_taken[$r->getURI()]=2;
  305. $this->anon++;
  306. }
  307. }
  308. return false;
  309. }
  310. $this->done[$r->getURI()] = true;
  311. $compress = false;
  312. if (is_a($r, 'Resource')) {
  313. if (is_a($r, 'BlankNode')) {
  314. //test if this blanknode is referenced somewhere
  315. $rbn = $this->model->find(null, null, $r);
  316. $compress = (N3SER_BNODE_SHORT || $this->styleCompress)
  317. && (
  318. count($rbn->triples) == 0
  319. || (count($rbn->triples) == 1 && $bEmbedded)
  320. );
  321. if ($compress) {
  322. $out.='[';
  323. } else {
  324. $out.='_:'.$r->getLabel();
  325. }
  326. } else {
  327. $this->doURI($r, $out);
  328. }
  329. }
  330. usort($ts->triples, 'statementsorter');
  331. $lastp = '';
  332. $out .= ' ';
  333. foreach ($ts->triples as $t) {
  334. $p = $t->getPredicate();
  335. if ($p === $lastp) {
  336. $out .= ' , ';
  337. } else {
  338. if ($lastp!='') {
  339. if ($this->stylePretty) {
  340. $out .= ";\n" . $strIndent;
  341. } else {
  342. $out .= ' ; ';
  343. }
  344. }
  345. $this->doURI($p, $out);
  346. $lastp = $p;
  347. }
  348. $out .= ' ';
  349. $o = $t->getObject();
  350. if (is_a($o, 'Literal')) {
  351. $l = $o->getLabel();
  352. if (strpos($l, LINEFEED) === false) {
  353. $long = false;
  354. } else {
  355. $long = true;
  356. }
  357. //try to be intelligent
  358. $quoteSingle = strpos($l, '\'') !== false;
  359. $quoteDouble = strpos($l, '"') !== false;
  360. if ($quoteSingle && !$quoteDouble) {
  361. $quoteChar = $long ? '"""' : '"';
  362. } else if ($quoteDouble && !$quoteSingle) {
  363. $quoteChar = $long ? '\'\'\'' : '\'';
  364. } else if ($quoteDouble && $quoteSingle) {
  365. //both quotation chars inside
  366. $quoteChar = $long ? '"""' : '"';
  367. $l = addslashes($l);
  368. } else {
  369. //no quotation chars
  370. $quoteChar = $long ? '"""' : '"';
  371. }
  372. $out .= $quoteChar . $l . $quoteChar;
  373. if ( $o->getLanguage()!='' ) {
  374. $out.='@'.$o->getLanguage();
  375. }
  376. if ( $o->getDatatype()!='' ) {
  377. $out.='^^<'.$o->getDatatype().'>';
  378. }
  379. }
  380. if (is_a($o, 'Resource')) {
  381. if ($this->debug) {
  382. print 'Doing object: '.$o->getURI().LINEFEED;
  383. }
  384. if (is_a($o, 'BlankNode')) {
  385. if ($this->styleNest && $this->styleCompress
  386. && !isset($this->done[$o->getURI()])
  387. ) {
  388. $this->doResource($o, true, $strIndent . ' ');
  389. $out .= MAGIC_STRING . $o->getURI() . MAGIC_STRING;
  390. //$out .= $this->resourcetext[$o->getURI()];
  391. $this->resourcetext_taken[$o->getURI()] = 1;
  392. } else {
  393. $out .= '_:'.$o->getLabel();
  394. }
  395. } else {
  396. $this->doURI($o, $out);
  397. }
  398. }
  399. }
  400. if ($compress) {
  401. $out .= ' ]';
  402. };
  403. $this->resourcetext[$r->getURI()]=$out;
  404. return true;
  405. }//function doResource(&$r)
  406. /**
  407. * Format a single URI
  408. * @param string $s
  409. * @return void
  410. * @access private
  411. **/
  412. function doURI(&$r, &$out)
  413. {
  414. if ($r->getURI() == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type') {
  415. $out .= 'a';
  416. return;
  417. }
  418. $ns = $r->getNamespace();
  419. if ($ns != '' && !isset($this->noPrefixes[$ns])) {
  420. $out .= $this->prefixes[$ns].':'.$r->getLocalName();
  421. } else {
  422. //Will this ever happen? It does, now.
  423. $out .= '<' . $r->getURI() . '>';
  424. }
  425. }
  426. /**
  427. * Fix the resourcetext for a blanknode where the _: construct was used
  428. * @param string $s
  429. * @param string $a
  430. * @access private
  431. * @return void
  432. **/
  433. function fixAnon($t,$a)
  434. {
  435. $t = preg_replace("/( \] $|^\[ )/", '', $t);
  436. return $a . $t;
  437. }
  438. }
  439. ?>