Skip to content

Instantly share code, notes, and snippets.

@Potherca
Last active January 15, 2022 15:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Potherca/7ab3c4a8d1eca011ef4b4e884b878da0 to your computer and use it in GitHub Desktop.
Save Potherca/7ab3c4a8d1eca011ef4b4e884b878da0 to your computer and use it in GitHub Desktop.

For a project at my employers we are working with the PHP Easy RDF library.

In order to help other developers understand how to do some basic things in Easy RDF, I have created an example that shows how to read a RDF file, find a node, remove that node or a property from that node and write the result back to the file, using Flysystem.

The Turtle document used in this example is an edited version of the test fixture used in the Solid Link Metadata Tests Suite.

A static HTML has been provided, as well as some quick-and-dirty PHP with a live example (also used to generate the HTML output).

To see the HTML visit https://bl.ocks.org/Potherca/raw/7ab3c4a8d1eca011ef4b4e884b878da0/

<!doctype html>
<meta charset="UTF-8">
<meta property="og:image" content="https://user-images.githubusercontent.com/195757/149627370-f1e57a0a-bbe6-44e8-90a6-59be4acf5611.png" />
<title>Easy RDF Example with Flysystem</title>
<link rel="icon" href="https://www.easyrdf.org/favicon.ico">
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
<style>
body {
background-color: #4D5760;
font-family: 'Roboto', sans-serif;
color: white;
}
dl {
display: flex;
flex-flow: row;
flex-wrap: wrap;
}
dd, dt {
border-bottom: 1px solid #ccc;
flex: 0 0 50%;
overflow: hidden;
padding: 0.15em 0;
text-overflow: ellipsis;
}
dd:last-of-type, dt:last-of-type {
border-bottom: none;
}
dd {
font-family: monospace;
margin-left: auto;
text-align: left;
}
details {
background-color: #4D5760;
border-radius: 0.5em;
border: 1px solid #ccc;
margin: 0.5em 0;
opacity: 0.65;
}
details:hover {
opacity: 1;
}
summary {
border-radius: 0.5em;
background-color: #4D5760;
color: white;
cursor: pointer;
font-weight: bold;
margin: 0;
padding: 0.25em 0.5em;
}
ol {
list-style-type: none;
list-style-position: inside;
margin-bottom: 1em;
padding-left: 0;
}
ol li > * {
padding: 0.3em;
}
ol li {
background: white;
border-radius: 0.5em;
border: 1px solid #666666;
margin: 1em;
}
pre, .php {
background-color: #eee;
border-radius: 0.5em;
position: relative;
white-space: pre-wrap;
}
pre {
padding: 1em;
color: #000;
}
section {
background-color: white;
border: 1px solid #ccc;
border-radius: 0.5em;
color: #333;
margin: 1em;
padding: 1em;
}
/*
li div[style]:not([id]),
li div[id] {
border-top-left-radius: 0.5em;
border-top-right-radius: 0.5em;
}
*/
.compare {
display: flex;
flex-wrap: wrap;
font-size: 0.85em;
justify-content: space-evenly;
}
.compare h3 {
text-align: center;
margin: 0;
}
.php {
line-height: 0.85em;
}
.php.php-inline {
border-radius: 0.5em;
display: inline;
line-height: inherit;
padding: 0.15em 0 0.35em 0.35em;
margin-right: 0.35em;
position: static;
white-space: inherit;
}
.php::before,
.turtle::before {
border-bottom-left-radius: 0.5em;
border-bottom: 1px solid;
border-left: 1px solid;
border-top-right-radius: 0.5em;
display: block;
font-family: sans-serif;
font-size: 0.8em;
padding: 0.3em;
position: absolute;
right: 0;
top: 0;
}
.php:not(.php-inline)::before {
background: #8892BF;
color: white;
content: 'PHP';
}
.turtle::before {
background: #0C4393;
color: white;
content: 'Turtle';
}
</style>
<h1>Easy RDF Example</h1>
<p>
This example shows how to read a RDF file, find a node, remove that node or
a property from that node and write the result back to the file, using Flysystem
</p>
<section>
<h2>Set things up</h2>
<p>
Creating a Flysystem and EasyRDF Graph is simplicity itself:
</p>
<div class="php"><code><span style="color: #000000">
<span style="color: #0000BB">&nbsp;&nbsp;$filesystem&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">Filesystem</span><span style="color: #007700">(new&nbsp;</span><span style="color: #0000BB">Local</span><span style="color: #007700">(</span><span style="color: #0000BB">__DIR__</span><span style="color: #007700">));<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$graph&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">EasyRdf_Graph</span><span style="color: #007700">();&nbsp;&nbsp;</span>
</span>
</code></div>
<p>
To make your live easier and the Turtle pretttier, it is possible to specify
specific namespaces to be used as a prefix:
</p>
<div class="php"><code><span style="color: #000000">
<span style="color: #0000BB">&nbsp;&nbsp;$namespace&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'https://purl.org/pdsinterop/link-metadata#'</span><span style="color: #007700">;<br />&nbsp;&nbsp;</span><span style="color: #0000BB">EasyRdf_Namespace</span><span style="color: #007700">::</span><span style="color: #0000BB">set</span><span style="color: #007700">(</span><span style="color: #DD0000">'lm'</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$namespace</span><span style="color: #007700">);</span>
</span>
</code></div>
</section>
<section>
<h2>Read a RDF file</h2>
<p>
The next thing we will want to do is read the contents from a file and feed it to the Graph to parse it.
</p>
<p>Read file <code>./input.ttl</code> as RDF resource:</p>
<div class="php"><code><span style="color: #000000">
<span style="color: #0000BB">&nbsp;&nbsp;$filename&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'./input.ttl'</span><span style="color: #007700">;<br /><br />&nbsp;&nbsp;</span><span style="color: #0000BB">$contents&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$filesystem</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">read</span><span style="color: #007700">(</span><span style="color: #0000BB">$filename</span><span style="color: #007700">);<br /><br />&nbsp;&nbsp;</span><span style="color: #0000BB">$graph</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">parse</span><span style="color: #007700">(</span><span style="color: #0000BB">$contents</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$format</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$filename</span><span style="color: #007700">);</span>
</span>
</code></div>
<p>
If we compare the original file contents with the parsed contents, we can see the graph is slightly different,
according to Easy RDF:
</p>
<div class="compare">
<div>
<h3>Original</h3>
<pre class="turtle"><code>@prefix : &lt;#&gt;.
@prefix tes: &lt;testDeleted/&gt;.
@prefix lin: &lt;https://purl.org/pdsinterop/link-metadata#&gt;.
@prefix stor: &lt;./&gt;.
@prefix te: &lt;testForget/&gt;.
@prefix dc: &lt;http://purl.org/dc/terms/&gt; .
@prefix rdfs: &lt;http://www.w3.org/2000/01/rdf-schema#&gt; .
tes: lin:deleted &quot;Because we say so&quot;.
stor:testExtraRedirect lin:redirectTemporary &lt;https://localhost/redirect-extra.html&gt;.
te: lin:forget &quot;You have the right to be forgotten&quot;;
dc:title &quot;Nested Test document&quot; ;
rdfs:comment &quot;Dummy file for testing metadata file in a parent directory&quot; ;
rdfs:comment &quot;It is also used to be directed to by the non-existent file 'redirectTemporary.ttl'&quot; .
stor:testPermanentRedirect lin:redirectPermanent &lt;https://localhost/redirect-permanent.html&gt;.
stor:testTempRedirect lin:redirectTemporary &lt;https://localhost/redirect-temporary.html&gt;.
</code></pre>
</div>
<div>
<h3>Parsed</h3>
<pre class="turtle"><code>@prefix lm: &lt;https://purl.org/pdsinterop/link-metadata#&gt; .
@prefix dc: &lt;http://purl.org/dc/terms/&gt; .
@prefix rdfs: &lt;http://www.w3.org/2000/01/rdf-schema#&gt; .
&lt;testDeleted/&gt; lm:deleted &quot;Because we say so&quot; .
&lt;testExtraRedirect&gt; lm:redirectTemporary &lt;https://localhost/redirect-extra.html&gt; .
&lt;testForget/&gt;
lm:forget &quot;You have the right to be forgotten&quot; ;
dc:title &quot;Nested Test document&quot; ;
rdfs:comment &quot;Dummy file for testing metadata file in a parent directory&quot;, &quot;It is also used to be directed to by the non-existent file 'redirectTemporary.ttl'&quot; .
&lt;testPermanentRedirect&gt; lm:redirectPermanent &lt;https://localhost/redirect-permanent.html&gt; .
&lt;testTempRedirect&gt; lm:redirectTemporary &lt;https://localhost/redirect-temporary.html&gt; .
</code></pre>
</div>
</div>
<p>
To see what the parsed graph looks like, we can use <span class="php php-inline"><code><span style="color: #000000">
<span style="color: #0000BB">$graph</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">dump</span><span style="color: #007700">()</span>
</span>
</code></span> to get nice output:
</p>
<div style='font-family:arial; font-weight: bold; padding:0.5em; color: black; background-color:lightgrey;border:dashed 1px grey;'>Graph: </div>
<div id='testDeleted/' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testDeleted/' style='text-decoration:none;color:blue'>testDeleted/</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:deleted</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;Because we say so&quot;</span></div></div></div>
<div id='testExtraRedirect' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testExtraRedirect' style='text-decoration:none;color:blue'>testExtraRedirect</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:redirectTemporary</span> <span style='font-size:130%'>&rarr;</span> <a href='https://localhost/redirect-extra.html' style='text-decoration:none;color:blue'>https://localhost/redirect-extra.html</a></div></div></div>
<div id='testForget/' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testForget/' style='text-decoration:none;color:blue'>testForget/</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:forget</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;You have the right to be forgotten&quot;</span></div>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>dc:title</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;Nested Test document&quot;</span></div>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>rdfs:comment</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;Dummy file for testing metadata file in a parent directory&quot;</span>, <span style='color:black'>&quot;It is also used to be directed to by the non-existent file 'redirectTemporary.ttl'&quot;</span></div></div></div>
<div id='testPermanentRedirect' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testPermanentRedirect' style='text-decoration:none;color:blue'>testPermanentRedirect</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:redirectPermanent</span> <span style='font-size:130%'>&rarr;</span> <a href='https://localhost/redirect-permanent.html' style='text-decoration:none;color:blue'>https://localhost/redirect-permanent.html</a></div></div></div>
<div id='testTempRedirect' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testTempRedirect' style='text-decoration:none;color:blue'>testTempRedirect</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:redirectTemporary</span> <span style='font-size:130%'>&rarr;</span> <a href='https://localhost/redirect-temporary.html' style='text-decoration:none;color:blue'>https://localhost/redirect-temporary.html</a></div></div></div>
</section>
<section>
<h2>Find a node</h2>
<p>
There are various ways to get a node from a graph. Which one is best for
you depends on the usecase you find yourself in.
</p>
<p>
Given that an RDF statement is: <code>(<strong>subject</strong>) (<strong>predicate</strong>) (<strong>object</strong>)</code>
</p>
<p>If we use the following for our example:</p>
<pre class="turtle"><code>&lt;testForget/&gt; lm:forget "You have the right to be forgotten"</code></pre>
<p>It is possible to get that resource based on its subject or predicate.</p>
<div class="php"><code><span style="color: #000000">
<span style="color: #0000BB">&nbsp;&nbsp;</span><span style="color: #FF8000">/*/&nbsp;Get&nbsp;Resource&nbsp;by&nbsp;subject&nbsp;/*/<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$resource&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$graph</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">resource</span><span style="color: #007700">(</span><span style="color: #DD0000">'&lt;testForget/&gt;'</span><span style="color: #007700">);<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #FF8000">/*/&nbsp;Get&nbsp;Resources&nbsp;by&nbsp;predicate&nbsp;/*/<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$resourceMatching&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$graph</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">resourcesMatching</span><span style="color: #007700">(</span><span style="color: #DD0000">'lm:forget'</span><span style="color: #007700">);<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #FF8000">/*/&nbsp;Check&nbsp;if&nbsp;a&nbsp;resource&nbsp;has&nbsp;a&nbsp;specific&nbsp;predicate&nbsp;/*/<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$hasPredicate&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$resource</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">hasProperty</span><span style="color: #007700">(</span><span style="color: #DD0000">'lm:forget'</span><span style="color: #007700">);<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #FF8000">/*/&nbsp;Get&nbsp;predicates,&nbsp;with&nbsp;prefix&nbsp;/*/<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$predicatesPrefixed&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$resource</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">properties</span><span style="color: #007700">();<br /><br />&nbsp;&nbsp;</span><span style="color: #FF8000">/*/&nbsp;Get&nbsp;predicates,&nbsp;as&nbsp;full&nbsp;URIs&nbsp;/*/<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$predicatesUris&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$resource</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">propertyUris</span><span style="color: #007700">();<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #FF8000">/*/&nbsp;Get&nbsp;value&nbsp;(i.e.&nbsp;object)&nbsp;based&nbsp;on&nbsp;subject&nbsp;and&nbsp;predicate&nbsp;/*/<br />&nbsp;&nbsp;</span><span style="color: #0000BB">$object&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$graph</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">get</span><span style="color: #007700">(</span><span style="color: #DD0000">'&lt;testForget/&gt;'</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'lm:forget'</span><span style="color: #007700">);<br />&nbsp;&nbsp;</span>
</span>
</code></div>
<p>It is possible to get all resources, so they can be iterated</p>
<div class="php"><code><span style="color: #000000">
<span style="color: #0000BB">&nbsp;&nbsp;$resources&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$graph</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">resources</span><span style="color: #007700">();</span>
</span>
</code></div>
<details>
<summary>Read 8 resources</summary>
<ol>
<li>
<div><a href='testDeleted/' style='text-decoration:none;color:blue'>testDeleted/</a></div>
<div id='testDeleted/' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testDeleted/' style='text-decoration:none;color:blue'>testDeleted/</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:deleted</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;Because we say so&quot;</span></div></div></div>
<dl>
<dt>Local Name</dt>
<dd></dd>
<dt>Properties</dt>
<dd>array (
0 => 'lm:deleted',
)</dd>
<dt>PropertyUris</dt>
<dd>array (
0 => 'https://purl.org/pdsinterop/link-metadata#deleted',
)</dd>
<dt>URI</dt>
<dd>testDeleted/</dd>
</dl>
</li>
<li>
<div><a href='testExtraRedirect' style='text-decoration:none;color:blue'>testExtraRedirect</a></div>
<div id='testExtraRedirect' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testExtraRedirect' style='text-decoration:none;color:blue'>testExtraRedirect</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:redirectTemporary</span> <span style='font-size:130%'>&rarr;</span> <a href='https://localhost/redirect-extra.html' style='text-decoration:none;color:blue'>https://localhost/redirect-extra.html</a></div></div></div>
<dl>
<dt>Local Name</dt>
<dd>testExtraRedirect</dd>
<dt>Properties</dt>
<dd>array (
0 => 'lm:redirectTemporary',
)</dd>
<dt>PropertyUris</dt>
<dd>array (
0 => 'https://purl.org/pdsinterop/link-metadata#redirectTemporary',
)</dd>
<dt>URI</dt>
<dd>testExtraRedirect</dd>
</dl>
</li>
<li>
<div><a href='testForget/' style='text-decoration:none;color:blue'>testForget/</a></div>
<div id='testForget/' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testForget/' style='text-decoration:none;color:blue'>testForget/</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:forget</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;You have the right to be forgotten&quot;</span></div>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>dc:title</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;Nested Test document&quot;</span></div>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>rdfs:comment</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;Dummy file for testing metadata file in a parent directory&quot;</span>, <span style='color:black'>&quot;It is also used to be directed to by the non-existent file 'redirectTemporary.ttl'&quot;</span></div></div></div>
<dl>
<dt>Local Name</dt>
<dd></dd>
<dt>Properties</dt>
<dd>array (
0 => 'lm:forget',
1 => 'dc:title',
2 => 'rdfs:comment',
)</dd>
<dt>PropertyUris</dt>
<dd>array (
0 => 'https://purl.org/pdsinterop/link-metadata#forget',
1 => 'http://purl.org/dc/terms/title',
2 => 'http://www.w3.org/2000/01/rdf-schema#comment',
)</dd>
<dt>URI</dt>
<dd>testForget/</dd>
</dl>
</li>
<li>
<div><a href='testPermanentRedirect' style='text-decoration:none;color:blue'>testPermanentRedirect</a></div>
<div id='testPermanentRedirect' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testPermanentRedirect' style='text-decoration:none;color:blue'>testPermanentRedirect</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:redirectPermanent</span> <span style='font-size:130%'>&rarr;</span> <a href='https://localhost/redirect-permanent.html' style='text-decoration:none;color:blue'>https://localhost/redirect-permanent.html</a></div></div></div>
<dl>
<dt>Local Name</dt>
<dd>testPermanentRedirect</dd>
<dt>Properties</dt>
<dd>array (
0 => 'lm:redirectPermanent',
)</dd>
<dt>PropertyUris</dt>
<dd>array (
0 => 'https://purl.org/pdsinterop/link-metadata#redirectPermanent',
)</dd>
<dt>URI</dt>
<dd>testPermanentRedirect</dd>
</dl>
</li>
<li>
<div><a href='testTempRedirect' style='text-decoration:none;color:blue'>testTempRedirect</a></div>
<div id='testTempRedirect' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testTempRedirect' style='text-decoration:none;color:blue'>testTempRedirect</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:redirectTemporary</span> <span style='font-size:130%'>&rarr;</span> <a href='https://localhost/redirect-temporary.html' style='text-decoration:none;color:blue'>https://localhost/redirect-temporary.html</a></div></div></div>
<dl>
<dt>Local Name</dt>
<dd>testTempRedirect</dd>
<dt>Properties</dt>
<dd>array (
0 => 'lm:redirectTemporary',
)</dd>
<dt>PropertyUris</dt>
<dd>array (
0 => 'https://purl.org/pdsinterop/link-metadata#redirectTemporary',
)</dd>
<dt>URI</dt>
<dd>testTempRedirect</dd>
</dl>
</li>
<li>
<div><a href='https://localhost/redirect-extra.html' style='text-decoration:none;color:blue'>https://localhost/redirect-extra.html</a></div>
<dl>
<dt>Local Name</dt>
<dd>redirect-extra.html</dd>
<dt>ReversePropertyUris</dt>
<dd>array (
0 => 'https://purl.org/pdsinterop/link-metadata#redirectTemporary',
)</dd>
<dt>URI</dt>
<dd>https://localhost/redirect-extra.html</dd>
</dl>
</li>
<li>
<div><a href='https://localhost/redirect-permanent.html' style='text-decoration:none;color:blue'>https://localhost/redirect-permanent.html</a></div>
<dl>
<dt>Local Name</dt>
<dd>redirect-permanent.html</dd>
<dt>ReversePropertyUris</dt>
<dd>array (
0 => 'https://purl.org/pdsinterop/link-metadata#redirectPermanent',
)</dd>
<dt>URI</dt>
<dd>https://localhost/redirect-permanent.html</dd>
</dl>
</li>
<li>
<div><a href='https://localhost/redirect-temporary.html' style='text-decoration:none;color:blue'>https://localhost/redirect-temporary.html</a></div>
<dl>
<dt>Local Name</dt>
<dd>redirect-temporary.html</dd>
<dt>ReversePropertyUris</dt>
<dd>array (
0 => 'https://purl.org/pdsinterop/link-metadata#redirectTemporary',
)</dd>
<dt>URI</dt>
<dd>https://localhost/redirect-temporary.html</dd>
</dl>
</li>
</ol>
</details>
</section>
<section>
<h2>Remove predicate from a resource for a specific namespace (URI base)</h2>
<p>
Lets say we want to remove all predicates that have the namespace
<code>https://purl.org/pdsinterop/link-metadata</code> from all the resource:
</p>
<div class="php"><code><span style="color: #000000">
<span style="color: #0000BB"><br />&nbsp;&nbsp;$namespace&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'https://purl.org/pdsinterop/link-metadata#'</span><span style="color: #007700">;<br /><br />&nbsp;&nbsp;foreach&nbsp;(</span><span style="color: #0000BB">$graph</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">resources</span><span style="color: #007700">()&nbsp;as&nbsp;</span><span style="color: #0000BB">$resource</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$predicates&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$resource</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">propertyUris</span><span style="color: #007700">();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(</span><span style="color: #0000BB">$predicates&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$predicate</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(</span><span style="color: #0000BB">strpos</span><span style="color: #007700">(</span><span style="color: #0000BB">$predicate</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$namespace</span><span style="color: #007700">)&nbsp;===&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$graph</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">deleteSingleProperty</span><span style="color: #007700">(</span><span style="color: #0000BB">$resource</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$predicate</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}</span>
</span>
</code></div>
<p>
If we compare the original dump with that after the predicate was removed,
we can see that all subjects that <em>only</em> had the predicate are removed.
</p>
<div class="compare">
<div>
<h3>Parsed before delete</h3>
<div style='font-family:arial; font-weight: bold; padding:0.5em; color: black; background-color:lightgrey;border:dashed 1px grey;'>Graph: </div>
<div id='testDeleted/' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testDeleted/' style='text-decoration:none;color:blue'>testDeleted/</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:deleted</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;Because we say so&quot;</span></div></div></div>
<div id='testExtraRedirect' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testExtraRedirect' style='text-decoration:none;color:blue'>testExtraRedirect</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:redirectTemporary</span> <span style='font-size:130%'>&rarr;</span> <a href='https://localhost/redirect-extra.html' style='text-decoration:none;color:blue'>https://localhost/redirect-extra.html</a></div></div></div>
<div id='testForget/' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testForget/' style='text-decoration:none;color:blue'>testForget/</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:forget</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;You have the right to be forgotten&quot;</span></div>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>dc:title</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;Nested Test document&quot;</span></div>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>rdfs:comment</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;Dummy file for testing metadata file in a parent directory&quot;</span>, <span style='color:black'>&quot;It is also used to be directed to by the non-existent file 'redirectTemporary.ttl'&quot;</span></div></div></div>
<div id='testPermanentRedirect' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testPermanentRedirect' style='text-decoration:none;color:blue'>testPermanentRedirect</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:redirectPermanent</span> <span style='font-size:130%'>&rarr;</span> <a href='https://localhost/redirect-permanent.html' style='text-decoration:none;color:blue'>https://localhost/redirect-permanent.html</a></div></div></div>
<div id='testTempRedirect' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testTempRedirect' style='text-decoration:none;color:blue'>testTempRedirect</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>lm:redirectTemporary</span> <span style='font-size:130%'>&rarr;</span> <a href='https://localhost/redirect-temporary.html' style='text-decoration:none;color:blue'>https://localhost/redirect-temporary.html</a></div></div></div>
</div>
<div>
<h3>Parsed after delete</h3>
<div style='font-family:arial; font-weight: bold; padding:0.5em; color: black; background-color:lightgrey;border:dashed 1px grey;'>Graph: </div>
<div id='testForget/' style='font-family:arial; padding:0.5em; background-color:lightgrey;border:dashed 1px grey;'>
<div><a href='testForget/' style='text-decoration:none;color:blue'>testForget/</a> <span style='font-size: 0.8em'>(EasyRdf_Resource)</span></div>
<div style='padding-left: 3em'>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>dc:title</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;Nested Test document&quot;</span></div>
<div><span style='font-size:130%'>&rarr;</span> <span style='text-decoration:none;color:green'>rdfs:comment</span> <span style='font-size:130%'>&rarr;</span> <span style='color:black'>&quot;Dummy file for testing metadata file in a parent directory&quot;</span>, <span style='color:black'>&quot;It is also used to be directed to by the non-existent file 'redirectTemporary.ttl'&quot;</span></div></div></div>
</div>
</div>
<p>
The resource that also had other predicates still exists, with those predicates intact.
</p>
</section>
<section>
<h2>Write result back to file</h2>
<p>
Once we have the graph to our liking, we can write it back to a file:
</p>
<div class="php"><code><span style="color: #000000">
<span style="color: #0000BB">$filesystem</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">update</span><span style="color: #007700">(</span><span style="color: #DD0000">'./output.ttl'</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$graph</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">serialise</span><span style="color: #007700">(</span><span style="color: #0000BB">$format</span><span style="color: #007700">));</span>
</span>
</code></div> </section>
<!doctype html>
<?php function highlight($code, $inline = false) : string
{
$tag = $inline ? 'span' : 'div';
return '<'. $tag .' class="php' . ($inline?' php-inline':'') . '">'.preg_replace(
'#&lt;\?php&nbsp;#',
'',
highlight_string('<?php ' . $code, true),
1
)."</$tag> ";
} ?>
<meta charset="UTF-8">
<meta property="og:image" content="https://user-images.githubusercontent.com/195757/149627370-f1e57a0a-bbe6-44e8-90a6-59be4acf5611.png" />
<title>Easy RDF Example with Flysystem</title>
<link rel="icon" href="https://www.easyrdf.org/favicon.ico">
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
<style>
a {
color: #4D5760;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
body {
background-color: #4D5760;
font-family: 'Roboto', sans-serif;
color: white;
}
dl {
display: flex;
flex-flow: row;
flex-wrap: wrap;
}
dd, dt {
border-bottom: 1px solid #ccc;
flex: 0 0 50%;
overflow: hidden;
padding: 0.15em 0;
text-overflow: ellipsis;
}
dd:last-of-type, dt:last-of-type {
border-bottom: none;
}
dd {
font-family: monospace;
margin-left: auto;
text-align: left;
}
details {
background-color: #4D5760;
border-radius: 0.5em;
border: 1px solid #ccc;
margin: 0.5em 0;
opacity: 0.65;
}
details:hover {
opacity: 1;
}
section > *:first-child {
margin-top: 0;
}
ol {
list-style-type: none;
list-style-position: inside;
margin-bottom: 1em;
padding-left: 0;
}
ol li > * {
padding: 0.3em;
}
ol li {
background: white;
border-radius: 0.5em;
border: 1px solid #666666;
margin: 1em;
}
pre, .php {
background-color: #eee;
border-radius: 0.5em;
position: relative;
white-space: pre-wrap;
}
pre {
padding: 1em;
color: #000;
}
section {
background-color: white;
border: 1px solid #ccc;
border-radius: 0.5em;
color: #333;
margin: 1em;
padding: 1em;
}
summary {
border-radius: 0.5em;
background-color: #4D5760;
color: white;
cursor: pointer;
font-weight: bold;
margin: 0;
padding: 0.25em 0.5em;
}
.compare {
display: flex;
flex-wrap: wrap;
font-size: 0.85em;
justify-content: space-evenly;
}
.compare h3 {
text-align: center;
margin: 0;
}
.php {
line-height: 0.85em;
}
.php.php-inline {
border-radius: 0.5em;
display: inline;
line-height: inherit;
padding: 0.15em 0 0.35em 0.35em;
margin-right: 0.35em;
position: static;
white-space: inherit;
}
.php::before,
.turtle::before {
border-bottom-left-radius: 0.5em;
border-bottom: 1px solid;
border-left: 1px solid;
border-top-right-radius: 0.5em;
display: block;
font-family: sans-serif;
font-size: 0.8em;
padding: 0.3em;
position: absolute;
right: 0;
top: 0;
}
.php:not(.php-inline)::before {
background: #8892BF;
color: white;
content: 'PHP';
}
.turtle::before {
background: #0C4393;
color: white;
content: 'Turtle';
}
</style>
<h1>Easy RDF Example</h1>
<section>
<p>
This example shows how to read a RDF file, find a node, remove that node or
a property from that node and write the result back to the file, using Flysystem.
</p>
<p>
the following will be explained:
</p>
<ul>
<li><a href="#section-setup">Setting things up</a></li>
<li><a href="#section-read">Reading a RDF file</a></li>
<li><a href="#section-find">Finding a node</a></li>
<li><a href="#section-remove">Removing a predicate from a resource</a></li>
<li><a href="#section-write">Writing the result back</a></li>
</ul>
</section>
<?php
/*/ Basic Setup /*/
use League\Flysystem\Adapter\Local;
use League\Flysystem\Filesystem;
require_once '../../vendor/autoload.php';
$filesystemRoot = __DIR__;
$adapter = new Local($filesystemRoot);
$filesystem = new Filesystem($adapter);
$prefix = 'lm';
$namespace = 'https://purl.org/pdsinterop/link-metadata#';
EasyRdf_Namespace::set($prefix, $namespace);
$graph = new EasyRdf_Graph();
/*/ This is the information we will be working with /*/
$filename = './input.ttl';
$format = 'turtle';
?>
<section>
<h2 id="section-setup">Setting things up</h2>
<p>
Creating a Flysystem and EasyRDF Graph is simplicity itself:
</p>
<?= highlight(<<<'PHP'
$filesystem = new Filesystem(new Local(__DIR__));
$graph = new EasyRdf_Graph();
PHP) ?>
<p>
To make your live easier and the Turtle pretttier, it is possible to specify
specific namespaces to be used as a prefix:
</p>
<?= highlight(<<<'PHP'
$namespace = 'https://purl.org/pdsinterop/link-metadata#';
EasyRdf_Namespace::set('lm', $namespace);
PHP) ?>
</section>
<section>
<h2 id="section-read">Reading a RDF file</h2>
<p>
The next thing we will want to do is read the contents from a file and feed it to the Graph to parse it.
</p>
<?php
$filename = './input.ttl';
$contents = $filesystem->read($filename);
$graph->parse($contents, $format, $filename);
$parsed = $graph->serialise($format);
$dump = $graph->dump();
?>
<p>Read file <code><?= $filename ?></code> as RDF resource:</p>
<?= highlight(<<<'PHP'
$filename = './input.ttl';
$contents = $filesystem->read($filename);
$graph->parse($contents, $format, $filename);
PHP) ?>
<p>
If we compare the original file contents with the parsed contents, we can see the graph is slightly different,
according to Easy RDF:
</p>
<div class="compare">
<div>
<h3>Original</h3>
<pre class="turtle"><code><?= htmlentities($contents) ?></code></pre>
</div>
<div>
<h3>Parsed</h3>
<pre class="turtle"><code><?= htmlentities($parsed) ?></code></pre>
</div>
</div>
<p>
To see what the parsed graph looks like, we can use <?= highlight('$graph->dump()', true) ?> to get nice output:
</p>
<?= $dump ?>
</section>
<section>
<h2 id="section-find">Finding a node</h2>
<?php
/**
* There are various ways to get a node from a graph. Which one is best for
* you depends on the usecase you find yourself in.
*/
/*/ It is possible to get all resources, so they can be iterated /*/
$resources = $graph->resources();
?>
<p>
There are various ways to get a node from a graph. Which one is best for
you depends on the usecase you find yourself in.
</p>
<p>
Given that an RDF statement is: <code>(<strong>subject</strong>) (<strong>predicate</strong>) (<strong>object</strong>)</code>
</p>
<p>If we use the following for our example:</p>
<pre class="turtle"><code>&lt;testForget/&gt; lm:forget "You have the right to be forgotten"</code></pre>
<p>It is possible to get that resource based on its subject or predicate.</p>
<?= highlight(<<<'PHP'
/*/ Get Resource by subject /*/
$resource = $graph->resource('<testForget/>');
/*/ Get Resources by predicate /*/
$resourceMatching = $graph->resourcesMatching('lm:forget');
/*/ Check if a resource has a specific predicate /*/
$hasPredicate = $resource->hasProperty('lm:forget');
/*/ Get predicates, with prefix /*/
$predicatesPrefixed = $resource->properties();
/*/ Get predicates, as full URIs /*/
$predicatesUris = $resource->propertyUris();
/*/ Get value (i.e. object) based on subject and predicate /*/
$object = $graph->get('<testForget/>', 'lm:forget');
PHP) ?>
<p>It is possible to get all resources, so they can be iterated</p>
<?= highlight(<<<'PHP'
$resources = $graph->resources();
PHP) ?>
<details>
<summary>Read <?= count($resources) ?> resources</summary>
<ol>
<?php foreach ($resources as $resource): ?>
<li>
<div><?= $resource->dumpValue() ?></div>
<?= $resource->dump() ?>
<dl>
<dt>Local Name</dt>
<dd><?= $resource->localName() ?></dd>
<?php if ($resource->prefix()): ?>
<dt>Prefix</dt>
<dd><?= $resource->prefix() ?></dd>
<?php endif; ?>
<?php if ($resource->properties()): ?>
<dt>Properties</dt>
<dd><?php var_export($resource->properties()) ?></dd>
<?php endif; ?>
<?php if ($resource->propertyUris()): ?>
<dt>PropertyUris</dt>
<dd><?php var_export($resource->propertyUris()) ?></dd>
<?php endif; ?>
<?php if ($resource->reversePropertyUris()): ?>
<dt>ReversePropertyUris</dt>
<dd><?php var_export($resource->reversePropertyUris()) ?></dd>
<?php endif; ?>
<?php if ($resource->types()): ?>
<dt>Types</dt>
<dd><?php var_export($resource->types()) ?></dd>
<?php endif; ?>
<dt>URI</dt>
<dd><?= $resource->getUri() ?></dd>
<?php if ((string) $resource->parseUri() !== $resource->getUri()): ?>
<dt>Parse Uri</dt>
<dd><?= $resource->parseUri() ?></dd>
<?php endif; ?>
</dl>
</li>
<?php endforeach; ?>
</ol>
</details>
</section>
<section>
<h2 id="section-remove">Removing a predicate from a resource</h2>
<p>
Lets say we want to remove all predicates that have the namespace
<code>https://purl.org/pdsinterop/link-metadata</code> from all the resource:
</p>
<?php
$namespace = 'https://purl.org/pdsinterop/link-metadata#';
$resources = $graph->resources();
foreach ($resources as $resource) {
$predicates = $resource->propertyUris();
foreach ($predicates as $predicate) {
if (strpos($predicate, $namespace) === 0) {
$graph->deleteSingleProperty($resource, $predicate);
}
}
}
?>
<?= highlight(<<<'PHP'
$namespace = 'https://purl.org/pdsinterop/link-metadata#';
foreach ($graph->resources() as $resource) {
$predicates = $resource->propertyUris();
foreach ($predicates as $predicate) {
if (strpos($predicate, $namespace) === 0) {
$graph->deleteSingleProperty($resource, $predicate);
}
}
}
PHP) ?>
<p>
If we compare the original dump with that after the predicate was removed,
we can see that all subjects that <em>only</em> had the predicate are removed.
</p>
<div class="compare">
<div>
<h3>Parsed before delete</h3>
<?= $dump ?>
</div>
<div>
<h3>Parsed after delete</h3>
<?= $graph->dump() ?>
</div>
</div>
<p>
The resource that also had other predicates still exists, with those predicates intact.
</p>
</section>
<section>
<h2 id="section-write">Writing the result back</h2>
<p>
Once we have the graph to our liking, we can write it back to a file:
</p>
<?php
$filesystem->update('./output.ttl', $graph->serialise($format));
?>
<?= highlight(<<<'PHP'
$filesystem->update('./output.ttl', $graph->serialise($format));
PHP) ?>
</section>
@prefix : <#>.
@prefix tes: <testDeleted/>.
@prefix lin: <https://purl.org/pdsinterop/link-metadata#>.
@prefix stor: <./>.
@prefix te: <testForget/>.
@prefix dc: <http://purl.org/dc/terms/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
tes: lin:deleted "Because we say so".
stor:testExtraRedirect lin:redirectTemporary <https://localhost/redirect-extra.html>.
te: lin:forget "You have the right to be forgotten";
dc:title "Nested Test document" ;
rdfs:comment "Dummy file for testing metadata file in a parent directory" ;
rdfs:comment "It is also used to be directed to by the non-existent file 'redirectTemporary.ttl'" .
stor:testPermanentRedirect lin:redirectPermanent <https://localhost/redirect-permanent.html>.
stor:testTempRedirect lin:redirectTemporary <https://localhost/redirect-temporary.html>.
@prefix dc: <http://purl.org/dc/terms/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<testForget/>
dc:title "Nested Test document" ;
rdfs:comment "Dummy file for testing metadata file in a parent directory", "It is also used to be directed to by the non-existent file 'redirectTemporary.ttl'" .
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment