Poznámka překladatele: V dokumentu jsou použity různé názvy vlastností, popřípadě funkcí, které mají jednoduše pochopitelné názvy - v anglickém jazyce. V českém překladu jejich názvy překládáme a původní anglický název uvádíme do závorky formou citace. Toto by mělo pomoci českému čtenáři, který neovládá anglický jazyk, aby lépe porozuměl zdrojovým kódům a dalším záležitostem ze světa FOAF.
Souhrn: Úvod do parsování FOAF a RDF užitím parseru RAP pro PHP.
Tento článek je průvodcem používání PHP k parsování dokumentů FOAF. FOAF znamená „přítel přítele“ (Friend of a Friend) a jde o zajímavou aplikaci RDF, která popisuje lidi a vztahy mezi nimi. Předpokládáme, že čtenář zná XML a PHP, ale má jen základní nebo žádné znalosti o RDF nebo FOAF a o tom, jak je parsovat.
RDF (Resource Description Framework) je formát navržený W3C (World Wide Web Consortium) k reprezentování metadat a znalostí na Webu.
RDF užívá grafový model k ukládání informací. Každý „uzel“ (node) v grafu je nazýván „zdroj“ (resource) a může být popsán pomocí URI. Některé uzly reprezentují text a jsou nazývány „literály“ (literal), jež jsou zvláštním typem zdrojů. Nemají žádný unikátní identifikátor, jsou popsány pouze textem, který obsahují. Oblouky spojující uzly jsou nazývány „vlastnosti“ (property) a musí být popsány pomocí URI. Oblouky mají vždy směr, tj. počáteční a koncový uzel.
Zde je příklad jednoduchého grafu RDF k reprezentování následujících faktů:

Jelikož jsou zdroje v RDF popsány pomocí URI, musíme zvolit URI pro každý z našich pojmů. V tomto případě http://example.com/people/john reprezentuje Johna,
http://example.com/orgs/hillview reprezentuje zaměstnání jako učitele a http://example.com/nouns/employer s
http://example.com/nouns/age reprezentují vlastnosti, které spojují tyto zdroje dohromady.
RDF graf může být zapsán jako seznam vztahů mezi uzly, tj. počáteční uzel, oblouk, koncový uzel. Tyto vztahy jsou nazývány „trojice“ (triple). Počáteční uzel je nazýván „předmět“ (subject), oblouk je nazýván „výrok“ (predicate) a koncový element se nazývá „objekt“ (object). Výše uvedený graf může být vypsán jako následující trojice:
Předmět: http://example.com/people/john Výrok: http://example.com/nouns/employer Objekt: http://example.com/orgs/hillview Předmět: http://example.com/people/john Výrok: http://example.com/nouns/age Objekt: „27“ Předmět: http://example.com/orgs/hillview Výrok: http://example.com/nouns/name Objekt: „Hill View“
Existuje několik způsobů, jak uložit RDF do souboru a jedním z nich je XML. XML verze výše uvedeného grafu může být:
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:noun="http://example.com/nouns/">
<rdf:Description rdf:about="http://example.com/people/john">
<noun:employer>
<rdf:Description rdf:about="http://example.com/orgs/hillview">
<noun:name>Hill View</noun:name>
</rdf:Description>
</noun:employer>
<noun:age>27</noun:age>
</rdf:Description>
</rdf:RDF>
Tento článek pojednává pouze o parsování XML formy RDF, jelikož jde o nejčastěji používanou formu na Webu. Pro úplnější úvod do RDF s kvanty příkladů nahlédněte do skvělé Příručky RDF od W3C (RDF Primer).
FOAF poskytuje kolem dvou tuctů užitečných termínů pro popis lidí. Ty mohou být vloženy do existujícího RDF nebo vytvořit základ pro soubor věnovaný FOAF, plně naplněný informacemi o osobě a lidech, které znají. Nejdůležitějším termínem je „osoba“ (Person), který (překvapivě!) reprezentuje osobu. Existuje sada dalších užitečných vlastností jako „jméno“ (name), „domovská stránka“ (homepage) a „zná“ (knows).
Typický soubor FOAF může vypadat takto:
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
>
<rdf:Description rdf:about="">
<dc:title>FOAF for Ian Davis</dc:title>
<dc:description>Friend-of-a-Friend description for Ian Davis</dc:description>
<dc:creator rdf:resource="#ian" />
</rdf:Description>
<foaf:Person rdf:ID="ian">
<foaf:name>Ian Davis</foaf:name>
<foaf:title>Mr</foaf:title>
<foaf:firstName>Ian</foaf:firstName>
<foaf:surname>Davis</foaf:surname>
<foaf:nick>iand</foaf:nick>
<foaf:mbox rdf:resource="mailto:iand@internetalchemy.org"/>
<foaf:mbox_sha1sum>69e31bbcf58d432950127593e292a55975bc55fd</foaf:mbox_sha1sum>
<foaf:homepage rdf:resource="http://internetalchemy.org/iand/"/>
<foaf:depiction rdf:resource="http://internetalchemy.org/iand/ianportrait.jpg"/>
<foaf:workplaceHomepage rdf:resource="http://www.innovateer.com/"/>
<foaf:schoolHomepage rdf:resource="http://www.rhul.ac.uk/" />
<foaf:made>
<rss:channel rdf:about="http://internetalchemy.org/index.rss">
<dc:title xml:lang="en">Internet Alchemy Weblog RSS Feed</dc:title>
<dc:description xml:lang="en">An RSS feed of weblog postings to the Internet Alchemy weblog</dc:description>
</rss:channel>
</foaf:made>
<foaf:interest>
<rdf:Description rdf:about="http://xmlns.com/foaf/0.1" rdfs:label="Friend-of-a-Friend"/>
</foaf:interest>
<foaf:interest>
<rdf:Description rdf:about="http://www.w3.org/2000/01/sw/" rdfs:label="Semantic Web Development"/>
</foaf:interest>
<foaf:interest>
<rdf:Description rdf:about="http://www.w3.org/RDF/" rdfs:label="Resource Description Framework (RDF)"/>
</foaf:interest>
<foaf:knows>
<foaf:Person>
<foaf:name>James Carlyle</foaf:name>
<foaf:mbox_sha1sum>9b7ac29183a3106b9ca8bc436d42f61ee284d147</foaf:mbox_sha1sum>
<foaf:depiction rdf:resource="http://internetalchemy.org/iand/pics/jamesCarlyle.jpg" />
<rdfs:seeAlso rdf:resource="http://www.takepart.com/about/foaf.rdf" />
</foaf:Person>
</foaf:knows>
</foaf:Person>
</rdf:RDF>
Tento soubor popisuje osobu (mě), jež se jmenuje Ian Davis, má titul „Mr“ (pan), křestní jméno Ian, ... toho už jste se ale určitě dovtípili sami. Existuje samozřejmě mnoho dalších zajímavých vlastností jako „vytvořil“ (made), která popisuje něco, co autor vytvořil, v tomto případě RSS kanál (RSS je formát RDF pro sdílení zpráv). Později se na tuto vlastnost podíváme blíže. Další zajímavou vlastností je „zná“ (knows). Ve výše uvedeném souboru obsahuje další osobu. Tato vlastnost by mohla obsahovat mnohem více lidí. Tento spojovací rys je jednou z věcí, které dělají FOAF tak zajímavým předmětem pro objevování RDF. Pro více informací o FOAF si přečtěte stránku projektu FOAF.
Pro PHP je dostupných velmi málo RDF parserů. Jedním z prvních byl RDF Parser spojený s projektem SourceForge „PHP XML Classes“. Šlo o port parseru Repat pro jazyk C do PHP, ale byl dokončen před rozvinutím specifikace RDF a PHP samotného. Spuštění pod PHP4 vyústí v množství nepříjemných chybových hlášení o použití zavržené syntaxe.
Současnější a více odpovídající parser je RAP - RDF API for PHP. Jde o PHP implementaci RDF API navrženého Sergeyem Melnikem a je RDF parserem, který budeme používat pro příklady v tomto článku.
Instalování RAP zahrnuje stažení poslední verze ze SourceForge a rozbalení zazipovaných souborů na místo někde na Vašem webovém serveru. K importování tříd do Vašeho skriptu potřebujete definovat konstantu RDFAPI_INCLUDE_DIR, která odkazuje do instalačního adresáře. RAP používá tuto konstantu interně, takže nemůžete vynechat tuto definici:
<?php
define('RDFAPI_INCLUDE_DIR', 'lib/rdfapi-php/api/');
require_once(RDFAPI_INCLUDE_DIR . 'RdfAPI.php');
?>
Tuto hlavičku musíte umístit do záhlaví každého PHP skriptu využívajícího RAP.
Ponořme se přímo dovnitř problému a parsujme. Tento první příklad vytváří RDF parser, parsuje soubor FOAF a vytváří seznam všech trojic, které najde:
$parser = new RdfParser();
$model = $parser->generateModel('http://internetalchemy.org/iand/foaf.rdf');
$it = $model->getStatementIterator();
while ($it->hasNext()) {
$statement = $it->next();
echo '<p>';
echo 'Předmět: ' . $statement->getLabelSubject() . '<br />';
echo 'Výrok: ' . $statement->getLabelPredicate() . '<br />';
echo 'Objekt: ' . $statement->getLabelObject();
echo '</p>';
}
První věcí, kterou tento kód udělá, je, že vytváří parser. Parser bude odpovědný za získání RDF z URL, kterou poskytneme, jeho parsování a konvertování do sady trojic. Další řádek dělá právě zmíněné parsování voláním metody parseru nazvané „generuj model“ (generateModel()) předložením URL mého souboru FOAF. Metoda generateModel vrací objekt modelu, který je podobný databázi, jež ukládá trojice. RAP má pouze jediný druh modelu a ukládá všechny trojice do paměti. Vyzrálejší RDF parsery typicky poskytují několik rozdílných implementací třídy modelu, které ukládají trojice ve více škálovatelných databázích.
Poznámka překladatale: Aktuální verze (0.8) knihovny RAP již obsahuje implementaci modelu ukládáného a načítaného z SQL databáze.
Třetí řádek volá metodu getStatementIterator(), jednu z metod modelu k vytvoření iterátoru. Můžete se možná divit, proč je metoda nazývána getStatementIterator a ne getTripleIterator(). Není na tom nic zvláštního, „tvzení“ (statement) je pouze dalším názvem pro trojici ve světě RDF.
Iterátory mají množství metod pro procházení trojicemi. Nejdůležitějšími z nich jsou „má další“ (hasNext()) a „další“ (next()). hasNext() vrací „pravda“ (true), pokud jsou iterátoru dostupné nějaké další trojice, zatímco next() vrací další trojici v sekvenci. Ano, trojice jsou v sekvenci, ale jsou uloženy náhodně a vy nemůžete nijak říci, jak budou trojice organizovány.
Několik dalších řádek jednoduše tiskne různé komponenty trojic užitím několika vhodných metod (getLabelSubject, getLabelPredicate a getLabelObject). Pro zdroje tyto metody vrací řetězec obsahující URI zdroje, pro literály vrací hodnotu literálu.
Řádky 3 až 11 vytváří idiom, který budeme využívat znovu a znovu. Protože množství trojic v modelu může být ohromné, RAP je více škálovatelný a dále poskytuje přístup k nim skrze iterátor raději než jejich načtení do pole. V dalších verzích, které budou využívat ukládání modelu do databází, bude změna iterátoru k vytvoření volání databáze bez nutnosti změny Vašeho kódu.
Obecná forma idiomu je:
Získej iterátor pro model
Dokud má iterátor další tvrzení
získej další tvrzení
Zde je část výstupu z mého souboru FOAF:
Předmět: http://internetalchemy.org/iand/foaf.rdf Výrok: http://purl.org/dc/elements/1.1/title Objekt: FOAF for Ian Davis Předmět: http://internetalchemy.org/iand/foaf.rdf Výrok: http://purl.org/dc/elements/1.1/description Objekt: Friend-of-a-Friend description for Ian Davis Předmět: http://internetalchemy.org/iand/foaf.rdf Výrok: http://purl.org/dc/elements/1.1/creator Objekt: http://internetalchemy.org/iand/foaf.rdf#ian Předmět: http://internetalchemy.org/iand/foaf.rdf#ian Výrok: http://www.w3.org/1999/02/22-rdf-syntax-ns#type Objekt: http://xmlns.com/foaf/0.1/Person
Podívejme se na získané trojice a pokusme se zjistit, co nám říkají. Pokud jste obeznámeni s RDF, potom můžete tuto část přeskočit. Řádky 1 až 3 reprezentují první trojici extrahovanou z RDF. Předmětem je řetězec http://internetalchemy.org/iand/foaf.rdf, což je náhodou URI souboru FOAF, takže tato trojice říká něco o vlastním souboru FOAF. Výrokem je http://purl.org/dc/elements/1.1/title, jež koresponduje s elementem „titulek“ (title) z jmenného prostoru Dublin Core. Jmenný prostor Dublin Core definuje slovník pro popis dokumentů a je velmi úspěšný a na Internetu široce užívaný. Objektem této trojice je „FOAF Iana Davise“ (FOAF for Ian Davis), takže tato trojice říká, že titulek souboru je „FOAF for Ian Davis“. Nečekané!
Následující trojice používá element „popis“ (description) z jmenného prostoru Dublin Core a poskytuje detailnější popis souboru, jmenovitě Friend-of-a-Friend description for Ian Davis.
Třetí trojice používá element „tvůrce“ (creator) z jmenného prostoru Dublin Core, ale místo jednoduchého textu jako hodnoty má za hodnotu URI http://internetalchemy.org/iand/foaf.rdf#ian. Tato URI vypadá, jako by odkazovala někam do vlastního souboru FOAF stejně, jak se užívá znak # a jméno na konci v adresách dokumentů HTML k odkazování na část dokumentu. Nicméně, místo odkazování na kus značkování referuje na zdroj v RDF modelu, jež je vytvořen z tohoto dokumentu. Někde v dokumentu RDF má něco definované rdf:ID „ian“, což je způsob RDF, jak popsat věci tak, že mohou být odkazovány dovnitř stejného dokumentu. Nebojte se, další trojice věci objasňuje.
Čtvrtá trojice na řádcích 13 až 15 říká něco o tomto zdroji. Má výrok http://www.w3.org/1999/02/22-rdf-syntax-ns#type, který koresponduje s RDF vlastností „typ“ (type) a objekt http://xmlns.com/foaf/0.1/Person. Aha! Náš první odkaz na FOAF. Tato trojice říká, že zdroj identifikovaný jako http://internetalchemy.org/iand/foaf.rdf#ian je členem třídy Person.
Dohromady tyto čtyři trojice říkají něco jako:
Soubor na adrese http://internetalchemy.org/iand/foaf.rdf má titulek „FOAF for Ian Davis“, popis „Friend-of-a-Friend description for Ian Davis“ a byl vytvořen osobou identifikovanou pomocí URI http://internetalchemy.org/iand/foaf.rdf#ian.
Je čas dělat něco zajímavějšího a začít se dotazovat RDF modelu. FOAF umožňuje popsat všechny druhy věcí o lidech a pravděpodobně tou nejdůležitější z nich je jméno. Víme, že http://internetalchemy.org/iand/foaf.rdf#ian odkazuje na zdroj, který je členem třídy „osoba“ (Person). Schéma FOAF nám říká, že existuje vlastnost nazvaná „jméno“ (name), která má URI http://xmlns.com/foaf/0.1/name. Takže trojice, které hledáme, mají následující vzor:
Předmět: http://internetalchemy.org/iand/foaf.rdf#ian Výrok: http://xmlns.com/foaf/0.1/name Objekt: ??
K získání trojic s tímto předmětem a výrokem z modelu vytvoříme objekt zdroje pro věci, které hledáme a vložíme do metody modelu nazvané „najít“ (find). Objekt zdroje můžete vytvořit dvěma způsoby: předáním kompletní URI zdroje, který chceme vytvořit nebo předáním jmenného prostoru a lokálního jména zdroje. Následující kód ilustruje oba způsoby této deklarace:
$personResource = new Resource('http://internetalchemy.org/iand/foaf.rdf#ian');
$foafNameResource = new Resource('http://xmlns.com/foaf/0.1/', 'name');
$matches = $model->find($personResource, $foafNameResource, NULL);
Metoda find() vrací další model, který obsahuje všechny trojice, jež odpovídají námi danému vzoru. Nyní můžeme použít iterátor modelu k vytisknutí těchto trojic:
$it = $matches->getStatementIterator();
echo '<p>http://internetalchemy.org/iand/foaf.rdf#ian má tyto jména:</p>';
while ($it->hasNext()) {
$statement = $it->next();
echo '<p>';
echo $statement->getLabelObject();
echo '</p>';
}
Samozřejmě, většina lidí má jen jedno jméno a ti, co jich mají více, stejně používají jen jedno z nich. Toto využijeme k malému zjednodušení. Vytvoříme funkci, která získá první tvrzení, které odpovídá vzoru a ignoruje zbytek a využijeme ji k napsání další funkce, která získá jméno osoby. Pro naše účely to bude fungovat skvěle, ale obecně bude nutné myslet na to, že může existovat více vlastností stejného typu.
function getFirstMatchingStatement(
$subjectResource, $predicateResource, $objectResource, $model) {
$statement = NULL;
$matches = $model->find($subjectResource, $predicateResource, $objectResource);
$statementIterator = $matches->getStatementIterator();
if ($statementIterator->hasNext()) {
$statement = $statementIterator->next();
}
return $statement;
}
function getNameForPerson($personResource, $model) {
$foafNameResource = new Resource('http://xmlns.com/foaf/0.1/', 'name');
$name = '';
$statement =
getFirstMatchingStatement($personResource, $foafNameResource, NULL, $model);
if ($statement) {
$name = $statement->getLabelObject();
}
return $name;
}
Nyní můžeme přepsat původní kód k jednoduchému získání jména:
$personResource = new Resource('http://internetalchemy.org/iand/foaf.rdf#ian');
echo '<p>http://internetalchemy.org/iand/foaf.rdf#ian má toto jméno:</p>';
echo '<p>';
echo getNameForPerson($personResource);
echo '</p>';
Nyní můžeme získat jméno jedné osoby, tak proč nezískat jména všech osob zapsaných v souboru FOAF. Kroky, které musíme udělat, jsou:
getNameForPerson.Prvním krokem je obvyklé volání metody find. Tentokrát hledáme předměty trojic, protože chceme všechny věci, které jsou typu Person. Je to podobné poslední trojici, kterou jsme viděli minule. Vzor trojice, který potřebujeme použít, vypadá asi takto:
Předmět:?? Výrok: http://www.w3.org/1999/02/22-rdf-syntax-ns#type Objekt: http://xmlns.com/foaf/0.1/Person
Druhým krokem je zase iterace. Zde je jeden způsob, jak tento skript napsat:
$rdfTypeResource =
new Resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'type');
$foafPersonResource = new Resource('http://xmlns.com/foaf/0.1/', 'Person');
$parser = new RdfParser();
$model = $parser->generateModel('http://internetalchemy.org/iand/foaf.rdf');
$people = $model->find(NULL, $rdfTypeResource, $foafPersonResource);
$personIterator = $people->getStatementIterator();
while ($personIterator->hasNext()) {
$personStatement = $personIterator->next();
echo
'<p>Jméno: ' . getNameForPerson($personStatement->getSubject(), $model) . '</p>';
}
Vypsání jmen je skvělé, ale celé FOAF je o vztazích. FOAF definuje vlastnost nazvanou „zná“ (knows) - http://xmlns.com/foaf/0.1/knows, která definuje spojení mezi dvěma lidmi. FOAF neuvádí přesný význam tohoto spojení kromě toho, že říká, že jedna osoba zná druhou. Známost může znamenat cokoliv od „kamarád mi o něm jednou řekl“ až po „sdílí se mnou má nejintimnější tajemství“. Jiná RDF schémata jako relationship, které napsal Eric Vitiello Jr., mohou být použita k rozšíření významu vlastnosti knows.
Algoritmus je pouze rozšířením toho předchozího:
Person.getNameForPerson.knows.Person.getNameForPerson užitím objektu trojice.Nyní můžeme tento algoritmus jednoduše převést do skutečného kódu s využitím techniky porovnávání vzorů a iterace.
První vzor je stejný jako minule, ale druhý je nový:
Předmět: ?Person Výrok: http://xmlns.com/foaf/0.1/knows Objekt: ??
Používám zde ?Person k určení zdroje, který byl nalezen s pomocí prvního vzoru.
Zde je kód, který vykonává celou práci:
$rdfTypeResource = new Resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'type');
$foafPersonResource = new Resource('http://xmlns.com/foaf/0.1/', 'Person');
$foafKnowsResource = new Resource('http://xmlns.com/foaf/0.1/', 'knows');
$parser = new RdfParser();
$model = $parser->generateModel('http://internetalchemy.org/iand/foaf.rdf');
$people = $model->find(NULL, $rdfTypeResource, $foafPersonResource);
$personIterator = $people->getStatementIterator();
while ($personIterator->hasNext()) {
$personStatement = $personIterator->next();
$personName = getNameForPerson($personStatement->getSubject(), $model);
if ($personName) {
$personKnows = $model->find($personStatement->getSubject(), $rdfsKnowsResource,NULL);
$knowsIterator = $personKnows->getStatementIterator();
while ($knowsIterator->hasNext()) {
$knowsStatement = $knowsIterator->next();
$knownPersonName = getNameForPerson($knowsStatement->getObject(), $model);
if ($knownPersonName) {
echo '<p>' . $personName . ' knows ' . $knownPersonName . '</p>';
}
}
}
}
Přidal jsem navíc kontrolu, aby bylo jisté, že každá osoba má definované jméno. Z kódu můžete vidět i algoritmus, kde občas děláme zbytečnou iteraci, protože spojujeme trojice dohromady; objekt jedné trojice se stává předmětem druhé. Dotazovací jazyky RDF jako RQL nebo Versa budou veškerou iteraci provádět skrytě, ale nejsou v současné době dostupné pro PHP, takže je to na Vás!
Nyní zkusme něco více ambiciózního, co zahrnuje parsování souborů FOAF lidí, které nějaké individuum zná. FOAF poskytuje vlastnost „vytvořil“ (made) - http://xmlns.com/foaf/0.1/made -, která specifikuje, že osoba něco vytvořila, obvykle dokument nebo RSS kanál. Je zde také uřitečná vlastnost definovaná specifikací RDF Schema nazvaná „podívej se také“ (seeAlso) - http://www.w3.org/2000/01/rdf-schema#seeAlso -, která je použita k odkázání na další dokument, obvykle opět RDF. Ve FOAF je typicky použita v popisu další osoby, kterou znáte a ona umožňuje agregátorům získat z Internetu vlastní soubor FOAF.
Poslední kus nástroje, který budeme potřebovat je další vlastnost FOAF nazvaná mbox_sha1sum (http://xmlns.com/foaf/0.1/mbox_sha1sum), která koresponduje s kryptografickým hashem e-mailové adresy osoby. FOAF definuje tuto vlastnost tak, že unikátně identifikuje osobu. (Každý mbox_sha1sum může patřit pouze jedné osobě, ale jedna osoba může mít více mbox_sha1sumů). V RDF může být stejný zdroj adresován různými URI, takže mbox_sha1sum může být použit ke spolehlivé detekci, že dva kusy FOAF mluví o stejné osobě.
Pokud se podíváme zpět na příklad FOAF na začátku tohoto článku, uvidíte sekci RDF využívající tyto tři vlastnosti, které popisují někoho, koho znám:
<foaf:Person>
<foaf:name>James Carlyle</foaf:name>
<foaf:mbox_sha1sum>9b7ac29183a3106b9ca8bc436d42f61ee284d147</foaf:mbox_sha1sum>
<rdfs:seeAlso rdf:resource="http://www.takepart.com/about/foaf.rdf" />
</foaf:Person>
Cílem tohoto finálního příkladu je získat soubory FOAF všech lidí, které znám a použít je k určení, které RSS kanály tito lidé publikují. (RSS je formát RDF pro publikování titulků zpráv). Můžete si je přidat do RSS čtečky a mít také přehled o aktuálních zprávách.
Použijeme následující algoritmus:
Person.getNameForPerson.knows.Person.getNameForPerson užitím objektu trojice.mbox_sha1sum osoby.seeAlso osoby.mbox_sha1sum i seeAlso, potom:mbox_sha1sum požadované hodnoty. Toto je známá osoba.Toto je trochu komplikovanější, než předchozí příklady, ale věřte mi, že nepoužíváme žádné jiné komplikované techniky. Je to stále porovnávání vzorů a iterace. Tak se podívejme na nové vzory, které budeme potřebovat. První je důležitý k získání mbox_sha1sum osoby. Je to vlastně to samé jako získání jména:
Předmět: ?Person Výrok: http://xmlns.com/foaf/0.1/mbox_sha1sum Objekt: ??
Vlastně můžeme vytvořit funkci podobnou té k získání jména osoby:
function getMailboxSha1sumForPerson($personResource, $model) {
$foafSha1sumResource = new Resource('http://xmlns.com/foaf/0.1/', 'mbox_sha1sum');
$mbox_sha1sum = '';
$statement = getFirstMatchingStatement($personResource, $foafSha1sumResource, NULL, $model);
if ($statement) {
$mbox_sha1sum = $statement->getLabelObject();
}
return $mbox_sha1sum;
}
Následující vzor je téměř identický:
Předmět: ?Person Výrok: http://www.w3.org/2000/01/rdf-schema#seeAlso Objekt: ??
Můžeme napsat ekvivalentní funkci. Poznamenejme, že obvykle dostaneme pouze první „seeAlso“ osoby. Toto je trochu „levné“, protože jedna osoba má často více těchto vlastností. Nicméně nás trochu tlačí čas, takže to necháme protentokrát být.
function getSeeAlsoForPerson($personResource, $model) {
$rdfsSeeAlsoResource = new Resource('http://www.w3.org/2000/01/rdf-schema#', "seeAlso");
$seeAlsoUri = '';
$statement = getFirstMatchingStatement($personResource, $rdfsSeeAlsoResource, NULL, $model);
if ($statement) {
$seeAlsoUri = $statement->getLabelObject();
}
return $seeAlsoUri;
}
Následující vzor potřebujeme k nalezení zdrojů, které vlastní určité mbox_sha1sum.
Předmět: ?? Výrok: http://xmlns.com/foaf/0.1/mbox_sha1sum Objekt: „?hodnota“
Tento vzor je nepatrně odlišný proti ostatním vzorům, které jsme použili. Objektem v tomto případě není zdroj, ale text nebo literál v terminologii RDF. Toto znamená, že musíme vytvořit objekt literálu a předat jej metodě find:
function getPersonBySha1sum($sha1sumValue, $model) {
$foafPersonResource = new Resource('http://xmlns.com/foaf/0.1/', 'Person');
$foafSha1sumResource = new Resource('http://xmlns.com/foaf/0.1/', 'mbox_sha1sum');
$personResource = NULL;
$statement = getFirstMatchingStatement(NULL, $foafSha1sumResource, new Literal($sha1sumValue), $model);
if ($statement) {
$personResource = $statement->getSubject();
}
return $personResource;
}
Následující vzor najde všechny věci vytvořené osobou:
Předmět: ?Person Výrok: http://xmlns.com/foaf/0.1/made Objekt: ??
K zjištění, že tato věc je RSS kanálem musíme použít vlastnost RDF nazvanou type (http://www.w3.org/1999/02/22-rdf-syntax-ns#type). Prostě se podíváme do modelu, jeslti je tam následující trojice. Pokud není, ignorujeme tuto věc a pokračujeme na další.
Předmět: ?madeThing Výrok: http://www.w3.org/1999/02/22-rdf-syntax-ns#type Objekt: http://purl.org/rss/1.0/channel
Nyní můžeme tyto dva vzory vložit s naším kódem mbox_sha1sum do nové funkce, která vytvoří seznam všech RSS kanálů vytvořených osobou s příslušným mbox_sha1sum daným URI jejího souboru FOAF:
function getChannelsMadeByPerson($sha1sum, $foafuri) {
$rdfTypeResource = new Resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'type');
$foafMadeResource = new Resource('http://xmlns.com/foaf/0.1/', 'made');
$rssChannelResource = new Resource('http://purl.org/rss/1.0/', 'channel');
$channels = array();
$parser = new RdfParser();
$model = $parser->generateModel($foafuri);
$personResource = getPersonBySha1sum($sha1sum, $model);
$madeThings = $model->find($personResource, $foafMadeResource, NULL);
$madeIterator = $madeThings->getStatementIterator();
while {$madeIterator->hasNext()) {
$madeStatement = $madeIterator->next();
// Vytvořila něco osoba?
// Je to RSS?
$statement = $getFirstMatchingStatement($madeStatement->getObject(), $rdfTypeResource, $rssChannelResource, $model);
if ($statement) {
// Přidej to do seznamu
$channels[] = $madeStatement->getLabelObject();
}
}
return $channels;
}
Nyní máme všechny komponenty k napsání PHP skriptu, který implementuje náš algoritmus
$rdfTypeResource = new Resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'type');
$foafPersonResource = new Resource('http://xmlns.com/foaf/0.1/', 'Person');
$foafKnowsResource = new Resource('http://xmlns.com/foaf/0.1/', 'knows');
$rdfsSeeAlsoResource = new Resource('http://www.w3.org/2000/01/rdf-schema#', 'seeAlso');
$people = $model->find(NULL, $rdfTypeResource, $foafPersonResource);
$personIterator = $people->getStatementIterator();
while ($personIterator->hasNext()) {
$personStatement = $personIterator->next();
$personName = getNameForPerson($personStatement->getSubject(), $model);
if ($personName) {
$personKnows = $model->find($personStatement->getSubject(), $rdfsKnowsResource,NULL);
$knowsIterator = $personKnows->getStatementIterator();
while ($knowsIterator->hasNext()) {
$knowsStatement = $knowsIterator->next();
$knownPerson = $knowsStatement->getObject();
$seeAlsoUri = getSeeAlsoForPerson($knownPerson, $model);
$knownPersonName = getNameForPerson($knownPerson, $model);
$knownPersonSha1sum = getMailboxSha1sumForPerson($knownPerson, $model);
if ($seeAlsoUri && $knownPersonName && $knownPersonSha1sum) {
$channels = getChannelsMadeByPerson($knownPersonSha1sum, $seeAlsoUri);
if (count($channels) > 0) {
echo '<p>' . $knownPersonName . ':</p>';
echo '<ul>';
while (list ($key, $channel) = each ($channels)) {
echo '<li>' . $channel . '</li>';
}
echo '</ul>';
}
}
}
}
}
Vytvořil jsem verzi tohoto kódu, která produkuje krásnější HTML výstup dostupnou jako živá služba. Kliknutím na odkaz „Show Source Code“ získáte kompletní kód z tohoto článku plus vylepšení.
Tento článek ukazuje, jak může být použito PHP k objevování sociálních sítí FOAF. Byly představeny dva jednoduché idiomy: porovnávání vzorů a iterace. Dohromady jsou tyto dvě techniky páteří každé aplikace zahrnující parsování RDF. Konečně jste v pozici, kdy můžete začít objevovat svět FOAF a tím pádem i RDF.
Definitivním zdrojem informací o RDF a místem, kde najdete formální specifikace je domovská stránka jazyka RDF publikovaná RDF.
Libby Miller napsal skvělý úvod do RDF Query zaměřený na knihovníky, ale může zaujmout kohokoliv zajímajícího se o pokročilé dotazovací techniky. Je zde také pokročilejší průzkum dotazovacích jazyků RDF, který je vyčerpávající a není určen začátečníkům.
Vytvořte svůj první soubor FOAF s pomocí nástroje FOAF-a-matic, který napsal Leigh Dodds nebo najděte někoho jiného s použitím našeho katalogu RDF zdrojů.
Ian Davis je britský vývojář, který sídlí v centrální Anglii. Je spoluzakladatelem a spolutvůrcem projektu Semantic Planet, stránky obhajující sémantický Web, kterou můžete najít na adrese http://www.semanticplanet.com. Ianův weblog najdete na adrese http://internetalchemy.org.
Tato článěk je chráněn copyrightem Iana Davise 2003. Je dovoleno reprodukovat tento dokument,pokud bude zachována tato zpráva a odkaz na originální dokument.
Copyright © 2003, Ian Davis a James Carlyle.