RDFLib e RDF-Schema
Saturday, November 29, 2003
Pubblico una breve sessione con RDFLib per l'interrogazione di un paio di RDF-Schema (RDFS) sicuramente noti ai blogger più incalliti.
Per comodità ho copiato precedentemente sul mio PC entrambi gli schemi utilizzati nell'esempio, ma indicando un URL come parametro
del metodo load lo schema può essere prelevato da un host remoto utilizzando il protocollo HTTP.
Partiamo con il creare un TripleStore, cioè un oggetto che andrà a contenere le triple definite dai due schemi. Fatto questo carichiamo il file RDFS di RSS 1.0, uno dei più noti formati di syndacation.
from rdflib.TripleStore import TripleStore as Store
# vocabulary for RDF e RDFS
import rdflib.constants as const
store = Store()
store.load('schemas/rss/1.0/schema.rdfs')
# utility function
def pr(l):
for _ in l: print _
Interroghiamo l'oggetto TripleStore richiedendo tutte le classi definite da RSS.
s = store.subjects(const.TYPE, const.RDFS_CLASS) pr(s) http://purl.org/rss/1.0/textinput http://purl.org/rss/1.0/item http://purl.org/rss/1.0/image http://purl.org/rss/1.0/channel
Le classi sono poche e per nulla interessanti. Carichiamo quindi uno schema più corposo, la versione 0.1 di Friend of a Friend (FOAF).
store.load('schemas/foaf/0.1/schema.rdfs') # merge triples
s = store.subjects(const.TYPE, const.RDFS_CLASS)
pr(s)
http://purl.org/rss/1.0/item
http://purl.org/rss/1.0/textinput
http://xmlns.com/foaf/0.1/Person
http://xmlns.com/foaf/0.1/OnlineChatAccount
http://purl.org/rss/1.0/channel
http://xmlns.com/foaf/0.1/Agent
http://xmlns.com/foaf/0.1/OnlineEcommerceAccount
http://xmlns.com/foaf/0.1/Organization
(...)
Da notare come RDFLib abbia automaticamente effettuato la fusione delle triple presenti nei
due schemi e l'uso di URI univoci eviti spiacevoli collisioni tra i due
vocabolari. Continuiamo chiedendo ad RDFLib di elencare le possibili proprietà
della classe FOAF chiamata Person.
from rdflib.Namespace import Namespace
foaf = Namespace('http://xmlns.com/foaf/0.1/')
props = store.possible_properties(foaf['Person'])
pr(props)
http://xmlns.com/foaf/0.1/firstName
http://xmlns.com/foaf/0.1/knows
http://xmlns.com/foaf/0.1/homepage
http://xmlns.com/foaf/0.1/mbox_sha1sum
http://xmlns.com/foaf/0.1/mbox
(...)
Il metodo possible_properties non si limita di fare un semplice
lookup delle propietà definite esplicitamente in Person,
ma include le propietà ereditate dalla classe. Visto che
Person è una sottoclasse di Agent RDFLib include
le proprietà di quest'ultima tra quelle di Person.
Infine RDFS permette di associare una etichetta ed un commento ad
ogni classe o propietà definita nello schema, i metodi comment
e label ci permettono di recuperare tali valori.
print store.comment(foaf['Agent']) An agent (eg. person, group, software or physical artifact). print store.label(foaf['mbox']) personal mailbox
Il Web Ontology Language (OWL) definisce in modo ancora più preciso cardinalità e relazioni tra classi, sottoclassi e proprietà. Attualmente RDFLib non fornisce tali funzionalià in modo nativo ma, visto che OWL segue lo stesso modello "a triple" definito da RDF, è possibile utilizzare l'API di RDFLib per eseguire query che comprendano le informazioni specificate da OWL.
Python, Webware & Cheetah
Wednesday, November 19, 2003
Cheetah è uno dei motori di templating più potenti e flessibili disponibili per Python. Un template Cheetah può essere molto complesso ed esistono svariati modi di utilizzarlo per generare pagine HTML accoppiandolo ad uno dei tanti web framework del pitone.
L'esempio che riporto di seguito è un utilizzo minimale e piuttosto atipico di Cheetah, ma che credo si adatti molto bene allo sviluppo di pagine web altamente dinamiche, dove solitamente la logica di presentazione dei dati ricopre un ruolo importante. Vista l'ottima integrazione di Cheetah con Webware, impiegherò quest'ultimo per sviluppare gli esempi mostrati in questo post.
Cominciamo col vedere il sorgente di SitePage, una servlet
Webware che verrà poi estesa dalle altre pagine del nostro ipotetico sito.
from Cheetah.Template import Template
from WebKit.Page import Page
class SitePage(Page):
""" Base site servlet """
_template = None
def title(self):
""" Title of the page on top
of the browser window """
return 'My Cool Website'
def htTitle(self):
""" Title of the page,
possibly with markup """
return 'My <strong>Cool</strong> Website'
def content(self):
""" Page content, sub-classes
should override """
return '[content placeholder]'
def footer(self):
""" Page footer """
return 'Copyright © 2003 XYZ Corp.'
def writeHTML(self):
request = self.request()
# load the template once
if not SitePage._template:
SitePage._template =
Template(file=request.serverSidePath('tmpl.html'))
# pass caller servlet as namespace
SitePage._template._ = self
# let template to output the HTML page
SitePage._template.respond(self.transaction())
La classe SitePage definisce una serie di metodi dal nome
familiare: content, footer, title.
Questi metodi restituiranno il codice HTML necessario per popolare il template
Cheetah definito esternamente e creato con un qualsiasi editor di pagine
web.
Tipicamente solo l'implementazione di content verrà poi ridefinita
dalle sottoclassi di SitePage. Il file tmpl.html
contiene il layout che accomuna le pagine dell'intero sito. Tale
file una volta in memoria verrà compilato da Cheetah e ad ogni richiesta
verranno invocati i metodi della servlet chiamante, i quali andranno a sostituire
con del markup i placeholder presenti all'interno del file di template.
I placeholder sono identificati dal nome dei metodi e vengono risolti da Cheetah in modo automatico. La servlet che richiama il template passa se stessa a quest'ultimo tramite un binding al simbolo _ (underscore). Il pattern per identificare un metodo della servlet diventa quindi $_.metodo.
Di seguito viene presentato il codice di una sottoclasse di SitePage
chiamata index che avrà come unico metodo content,
che costituisce il contenuto principale della pagina.
from SitePage import SitePage
from datetime import date
class index(SitePage):
""" Home page for my site """
def content(self):
return "<p>Hi there, it's %s</p>" % date.today()
Come si evince dell'esempio è molto semplice "iniettare" codice HTML all'interno del template. Alcuni moduli come htmlgen o SimpleHTMLGen, rendono ancora più "pythonic" generare markup HTML. In particolare utilizzando SimpleHTMLGen l'esempio sopra può essere riscritto in:
from SitePage import SitePage
from datetime import date
from SimpleHTMLGen import html
class index(SitePage):
""" Home page for my site """
def content(self):
return html.p("Hi there, it's %s" % date.today())
SimpleHTMLGen si occupa di chiudere correttamente tutti i tag (secondo la sintassi XHTML, non HTML) e di effettuare l'escape dei caratteri speciali. Un esempio che dimostri in maniera più convincente l'utilità di questo modulo è la generazione di una lista (UL) di link:
from SitePage import SitePage
from SimpleHTMLGen import html
class cool(SitePage):
""" Show a list of cool links """
def content(self):
# link's text and URL
data = [('Spam', 'http://www.foo.com/'),
('Eggs', 'http://www.bar.com/')]
return html.ul(c=[html.li(html.a(text, href=url)) for text, url in data])
È facile immaginare una serie di estensioni a questo meccanismo.
Una potrebbe essere quella di parametrizzare il nome del template in modo
che sia ridefinibile dalle sottoclassi di SitePage senza essere
costretti a riscrivere il metodo writeHTML. Ma questa sarà
materia per un altro post.
Per concludere, ritengo che utilizzare Python per la generazione di codice HTML anziché affidarsi ai mini-linguaggi presenti in molti sistemi di templating sia l'approccio da preferire, visto che la logica associata alla presentazione dei dati tende a diventare più complessa con il crescere del sito. Avendo cura di generare solo il codice HTML strettamente necessario e delegando i dettagli estetici ai fogli di stile (CSS) si riesce ad avere codice più leggibile e manutenibile.
Aggiornamento: il file pwc-src.zip contiene i sorgenti dell'ultimo esempio proposto.
C# 2.0
Monday, November 3, 2003
Il Microsoft Professional Developer Conference di Los Angeles è da poco terminato e le prime informazioni sulle novità del linguaggio cominciano a circolare sul web.
Inizialmente pensavo di scrivere un lungo post dilungandomi sui Generics,
su yield return, sui Partial Types ed i metodi anonimi,
facendo notare come queste funzionalità fossero eleganti rattoppi o idee
rubate ad altri linguaggi senza sponsor miliardari... ma poi ho deciso di
non addentrarmi in questioni tecniche. Il perché di questo ripensamento
è presto detto:
- Se pensate che C# sia favoloso è molto difficile che io riesca a convincervi del contrario.
- Se siete critici riguardo al linguaggio di Microsoft avrete sicuramente già trovato di meglio.
- Se cadete dalle nuvole leggendo questo messaggio allora può aiutarvi "Revenge of the nerds" di Paul Graham. Leggetelo, è illuminante.