Semantic Web

III parte: Web Ontology Language (OWL)di e

Il web semantico si propone di dare un "senso", aggiungere "significato" alle pagine web e ai collegamenti ipertestuali, dando la possibilità di cercare in modo diverso rispetto alle tradizionali ricerche testuali. In questo articolo introdurremo OWL: Web Ontology Language.

Introduzione

Il Semantic Web racchiude un insieme di tecnologie con l‘obiettivo di rendere le informazioni comprensibili ed elaborabili da programmi. Lo scopo è di creare nuova conoscenza traendo delle conclusioni che sono implicate dalla base di conoscenza iniziale. Il Semantic Web è uno stack tecnologico formato dalla stratificazione di più componenti in cui ogni livello è la base per gli standard definiti ai livelli superiori.

Nei precedenti articoli abbiamo parlato di RDF e RDFS, le fondamenta su cui poggia lo stack del Web Semantico [MOKA_SEM_I], [MOKA_SEM_II]. In questo articolo introdurremo OWL: Web Ontology Language.

Figura 1 - Semantic Web Stack

Ontologie

Il web semantico si propone di dare un "senso", aggiungere "significato" alle pagine web e ai collegamenti ipertestuali, dando la possibilità  di cercare in modo diverso rispetto alle tradizionali ricerche testuali.
Tutto questo non in virtù di sistemi di intelligenza artificiale, reti neurali o ragionamenti sull‘etimologia delle parole, ma "semplicemente" grazie all‘uso di un sistema di marcatura dei documenti, all‘adozione di un linguaggio gestibile da applicazioni e tramite l‘introduzione di vocabolari specifici, creando insiemi di frasi sulle quali poter definire relazioni fra elementi marcati.

Il web semantico per funzionare deve disporre di informazioni strutturate e di regole di deduzione, in modo da risalire alle informazioni richieste da una interrogazione.

La base di conoscenza del Semantic Web viene espressa tramite RDF, che consente di esprimere delle triple nella forma di soggetto, predicato e oggetto [MOKA_SEM_1]. Nonostante RDF sia processabile da un programma, serve unicamente per descrivere modelli di dati. Tuttavia quando si usa RDF per descrivere gli oggetti di un particolare dominio è indispensabile tenere conto della natura di tale dominio, in termini di categorie o classi di oggetti, di relazioni possibili tra gli oggetti e di regole cui queste relazioni devono sottostare per essere "valide". A questo "insieme di meta-informazioni valide per un dominio di interesse", ci si riferisce solitamente col nome di "ontologia".

Avendo a disposizione un‘ontologia è possibile scrivere un ragionatore (un programma in grado di applicare regole) che partendo da una base di conoscenza definita su questa ontologia tragga delle conclusioni, o meglio: sia in grado di inferire.

Partendo da un‘ontologia di riferimento e da un modello di dati espresso in OWL, un agente software "intelligente" può usare queste meta-informazioni per fare dei semplici ragionamenti sui dati: se Tizio è il miglior amico di Caio allora Tizio conosce Caio. Questo processo chiamato Reasoning ("ragionamento") è uno dei principi cardine del Semantic Web, in quanto consente di inferire nuova conoscenza ricavando affermazioni che non erano specificate esplicitamente nei dati iniziali; tante più sono le caratteristiche o vincoli strutturali del dominio espresse con linguaggio ontologico, tanto più potente potrà  essere il ragionamento applicabile ai dati iniziali.
RDFS di per sà© non è sufficiente a descrivere tali informazioni in modo da permettere a un agente di effettuare ragionamenti complessi in completa autonomia; si limita a definire le relazioni di ereditarietà , il concetto di risorsa, di proprietà , di tipo, di collezione e poco altro, e non riesce a descrivere completamente le relazioni che intercorrono tra le risorse.
Ad esempio, in RDFS non è possibile dire "una persona può avere una sola madre": un ragionatore RDFS non è quindi in grado di segnalare che una base di dati in cui una persona ha due madri non è valida.

Un‘ontologia rappresenta la concettualizzazione di un dominio, ossia una descrizione formale di un insieme di concetti e delle relazioni che intercorrono tra essi. OWL permette proprio questo.

Figura 2 - OWL, RDF e XML

Web Ontology Language: OWL

"Ontologia" nell‘ambito filosofico si riferisce allo studio dell‘esistenza. In informatica si intende con "ontologia" una descrizione dei concetti e delle relazioni esistenti comprensibili da una macchina, che permette la classificazione e il ragionamento induttivo. OWL permette di rappresentare un‘ontologia e quindi la descrizione di una specifica concettualizzazione.

Il Web Ontology Language (OWL) è un linguaggio di markup per rappresentare esplicitamente significato e semantica di termini con vocabolari e relazioni tra i termini. Tale rappresentazione dei termini e delle relative relazioni è chiamata ontologia (informatica). L‘obiettivo è permettere ad applicazioni software di elaborare il contenuto delle informazioni dei documenti scritti in OWL. OWL è uno standard W3C che fa parte del W3C Semantic Web framework [W3C_OWL].

Legato alle basi di conoscenza e alle ontologie troviamo il concetto di inferenza con il quale si vuole indicare il meccanismo di deduzione di nuove informazioni da una base di conoscenza. Inferire X significa concludere che X è vero; un‘inferenza è la conclusione tratta da un insieme di fatti o circostanze [WP_INF].

Il linguaggio OWL parte dai concetti base di RDFS e li estende introducendo costrutti per la definizione delle relazioni tra le classi e delle relative cardinalità .

OWL è rilasciato in tre diverse versioni, con complessità  e potere espressivo crescenti secondo un sistema a "scatole cinesi": OWL-Lite, OWL-DL e OWL-Full [MOKA_SEM].

Figura 3 - OWL Lite ,OWL DL e OWL Full

Concetti base di OWL

In questo paragrafo verranno introdotti gli aspetti più salienti di OWL e si parlerà  di:

  • Classi
  • Proprietà 
  • Gerarchie di classi
  • Gerarchia di proprietà 
  • Tipologie di proprietà  Object Property e Datatype Property
  • Proprietà  inverse
  • Caratteristiche di una proprietà : 1. Transitive (Transitive); 2. Funzionali (Functional); 3. Simmetriche (Symmetric)
  • Domini e range
  • Restrizioni di proprietà  (facets / role restriciton)
  • Individui

Per prendere dimestichezza con questi concetti si utilizzerà  come strumento l‘editor open source Protà©gà© per la definizione di ontologie OWL. Innanzitutto è bene precisare che un‘Ontologia OWL è costituita da tre principali componenti: individui, proprietà  e classi:

  • Individui (individuals / instances): rappresentano gli oggetti del dominio di interesse
  • Proprietà  (properties / slots / roles): sono relazioni binarie (collegano due oggetti per volta) tra individui
  • Classi (Class / Concepts): sono insiemi di individui

La figura 4 mostra un semplice esempio dove cinque individui (Stefano, Alessandro, Milano, Bologna, Aran) sono raggruppati in tre classi (Persone, Città , Animali) e messi in relazione attraverso due tipi di proprietà  ("vive" e "ha_animale"). Le classi sono rappresentate come ovali vuoti, gli individui sono rombi e le proprietà  sono archi direzionati.

Figura 4 - Individui, Proprietà  e classi

Le classi OWL possono essere organizzate in gerarchie di superclassi e sottoclassi dette tassonomie.

Classi e istanze

Le classi descrivono i concetti del dominio di interesse. Le classi sono una rappresentazione concreta di un concetto (Concept) e specificano le caratteristiche che devono essere soddisfatte per appartenere a tale classi. Ad esempio la classe Cane descrive le caratteristiche che devono avere gli individui per essere catalogati come cane.
Le classi possono essere messe in gerarchia (si parla di tassonomie) per specializzare ulteriormente la superclasse. Le classi figlie rappresentano i concetti più specifici della superclasse.

Per assimilare meglio questi concetti, verrà  introdotto un esempio pratico creando una gerarchia di classi, o per meglio dire una tassonomia, con Protà©gà©. Il primo passo è la creazione di un nuovo progetto OWL/RDF.

Figura 5 - Creazione di un nuovo progetto Protà©gà©

Il controllo principale della GUI di Protà©gà© è la Barra dei Componenti, che permette di navigare tra i diversi elementi dell‘ontologia (classi, proprietà , individui) in fase di creazione dell‘ontologia stessa.

Figura 6: Il pannello dei componenti di Protà©gà©

Creato il progetto, si parte da un‘ontologia vuota che contiene la sola classe owl:Thing. La classe owl:Thing è la classe da cui vengono derivate tutte le altre classi dell‘Ontologia (è l‘analoga alla classe java.lang.Object di Java tanto per capirsi). Per inserire una nuova classe nell‘ontologia ci si deve posizionare sulla classe di cui si vuole creare una sotto-classe, schiacciare il tasto destro del mouse e selezionare l‘opzione Create Subclass oppure agire direttamente sull‘icona grafica (fig. 7(D)).


Figura 7 - Protà©gà© OWL Class Panel

Viene creata una prima classe, figlia di owl:Thing, di nome Animale. Creata la classe Animale, si procede allo stesso modo creando anche la sottoclasse Cane (figlia di Animale). E‘ importante notare che tutte le istanze della classe figlia (Cane) sono istanze della classe madre (Animale) che, nell‘esempio, significa dire che tutti gli individui appartenenti all‘insieme Cane, appartengono anche all‘insieme Animale (Cane è un sottoinsieme di Animale).

Figura 8 - Gerarchia Thing, Animale e Cane

Si procede ulteriormente creando la classe Gatto (ereditando da Animale) e PastoreTedesco (quest‘ultima ereditando da Cane). La figura 9 mostra la tassonomia appena presentata con Pròtègè.

Figura 9 - La tassonomia proposta

OWL assume di default che le classi possano "sovrapporsi" (overlap) se non si dichiara esplicitamente il contrario.

Prevedere che due classi siano disgiunte vuole dire che un individuo può essere un‘istanza di una sola classe. Riprendendo l‘esempio degli animali, un individuo può appartenere sia alla classe Gatto che alla classe Cane. Ciò ovviamente non è realisitico. Disgiungendo le classi Cane e Gatto si ottiene una restrizione tale per cui un individuo può essere o un Cane o un Gatto. Per dichiarare che le due classi Cane e Gatto sono tra loro disgiunte, basta selezionare una qualsiasi delle due classi sorelle, premere il pulsante "Add all siblings..." (fig. 7(B)) e selezionare l‘opzione "Mutually between all siblings" (fig. 7 (B1)) nella sezione "Disjoints".

Figura 10 - Disgiunzione di classi

Proprietà 

Le proprietà  sono relazioni binarie che collegano due individui: ad esempio la proprietà  haFiglio può mettere in relazione un‘istanza Padre con un‘istanza Figlio. OWL ammette due tipologie principali di proprietà : le proprietà  object e le proprietà  datatype:

  • Object Property: collegano individui a individui
  • Datatype Property: collegano individui a dati aventi valori di tipo ammissibile per XML e/o RDF (int, string, ...)
  • Annotation Property: tipo di proprietà  appositamente definita per inserire delle annotazioni

Ad esempio dire "Alessandro ha sorella Laura", allora "ha_sorella" è una object property che collega l‘individuo Alessandro all‘individuo Laura. Dire che "Stefano ha_età  37", "ha_età " è una proprietà  datatype che relaziona l‘individuo Stefano al dato literal 37 (xml:Integer).

Figura 11 - Esempi di proprietà  Object property e Datatype proprerty>>

In modo analogo a quanto avviene con le classi e sottoclassi, le proprietà  possono essere messe in gerarchia e le "sotto-proprietà " diventano una specializzazione (rdfs:subPropertyOf) delle proprietà  di partenza. Ad esempio la proprietà  "ha_madre" può essere una specializzazione (sub-property) della proprietà  "ha_genitore".

Per definire le proprietà  in Protà©gà© bisogna selezionare il pannello Properties. Analogamente al pannello delle Classi anche questo pannello è suddiviso in due sezioni principali: la parte sinistra mostra la gerarchia delle proprietà  mentre la parte destra consente di caratterizzare la proprietà  selezionata.


Figura 12 - Protà©gà© OWL Properties Panel

Inserire una nuova proprietà  è del tutto simile ad inserire una nuova classe. L‘unica differenza è che è possibile creare una proprietà  senza antenati. Per creare la proprietà  è necessario selezionare l‘opportuno panel della tipologia di proprietà  che si vuole creare (fig. 12(A1) per le object property, Fig12(A2) per le datatype property e Fig12(A3) per le annotation property) e selezionare il pulsante Create Property (fig.12 (A4)) specificandone il nome.

Ã? importante sapere che ogni proprietà  può avere la sua inversa. Se una proprietà  collega l‘individuo A all‘individuo B, la sua proprietà  inversa collega allora l‘individuo B ad A. Con Protà©gà© questo si ottiene creando dapprima una proprietà  e poi selezionando il pulsante Create new inverse property (fig. 12 (D)).

Figura 13 - Proprietà  Inversa

Sulle proprietà  si possono definire diverse caratteristiche come Simmetria, Transitività  e Funzionalità : per definire tali caratteristiche bisogna utilizzare i check box della vista Properties (vedere fig. 12 (C)).

Se la proprietà  P che relaziona un individuo A ad un individuo B è simmetrica, questo implica che anche l‘individuo B è relazionato all‘individuo A mediante la proprietà  P. Nell‘esempio sotto (vedere figura 14), l‘individuo Stefano è relazionato con l‘individuo Alessandro mediante una proprietà  simmetrica "haVicinodiCasa". Questo implica che Alessandro è vicino di casa di Stefano.

Data una proprietà  P che relaziona un individuo A a un individuo B e anche un individuo B a un individuo C, se la proprietà  P è transitiva, allora possiamo inferire che l‘individuo A è relazionato con l‘individuo C mediante la proprietà  P. Nell‘esempio sotto, la proprietà  "haCollega" è transitiva.

Se una proprietà  P è funzionale, per un dato individuo, ci può essere al massimo un individuo in relazione con tale individuo mediante la proprietà  P. Nell‘esempio, l‘individuo Stefano è relazionato con l‘individuo Rosy mediante una proprietà  funzionale "haMadre. Sempre mediante la proprietà  funzionale "haMadre" l‘individuo Stefano è relazionato con l‘individuo Rosalba. Questo implica che Rosy e Rosalba sono la stessa persona.

Figura 14 - Esempi di proprietà  simmetriche, transitive e funzionali

Dominio e Range dell proprietà 

Le proprietà  hanno un dominio (domain) e un codominio (range). In matematica il dominio di una funzione è l‘insieme su cui la funzione è definita, mentre il codominio è l‘insieme dei valori che la funzione può assumere. In OWL il dominio di una proprietà  è rappresentato dalla classe o dall‘insieme di classi contenenti individui sui quali la proprietà  ha origine. Il range di una proprietà  rappresenta invece la classe o l‘insieme di classi contenenti individui sui quali la proprietà  ha destinazione.

Nell‘esempio "pizzaiolo" di CO-ODE [COODE], sul quale fonda il tutorial Protà©gà© [TUTP], si definiscono le tassonomie di Pizze, Ingredienti (Pizze Topping) ed una serie di proprietà  tra cui haIngrediente (hasTopping). In tale esempio la proprietà  hasTopping ha come dominio la classe Pizza e come codominio la classe PizzaTopping. Tale proprietà  quindi collega gli individui di classe Pizza agli individui di classe PizzaTopping.

Per specificare il dominio della proprietà , nel pannello delle proprietà  bisogna selezionare (bottone "Specialise Domain") la classe Pizza come dominio, e la classe PizzaTopping come Range (bottone "Specialise Range").


Figura 15 - Esempio di dominio e range

Restrizioni sulle classi

Un tipico utilizzo delle proprietà  è nella definizione di restrizioni di classe, ovvero di restrizioni dell‘insieme di individui che possono appartenere ad una classe. Le restizioni OWL possono essere dei tre seguenti tipi:

  • Cardinalità  (Cardinality Restrictions)
  • hasValue (hasValue Restrictions)
  • quantità  (Quantifier Restrictions: existential quantifier e universal quantifier)

Per settare le restrizioni con Protà©gà© si utilizza il bottone "Create restrictions ...". Le restrizioni di cardinalità  specificano, per una data proprietà , il numero di occorrenze (p.e.: il minimo numero (Minimum Cardinality), il massimo numero (Maximum Cardinality)) con cui la stessa proprietà  potrà  essere applicata alla classe.

Le "restrizioni di quantità " sono composte da un quantificatore, da una proprietà  e da un argomento (o filler). Le restrizioni che utilizzano il quantificatore esistenziale (indicato dal segno di "E" inversa) sono dette restrizioni esistenziali (Existential Restrictions - someValuesFrom) mentre le restrizioni che utilizzano il quantificatore universale (idicato dal segno di "A" inversa) sono dette restrizioni universali (Universal Restrictions - allValuesFrom).

Riprendendo l‘esempio "pizzaiolo" di CO-ODE, applicando una restrizione del tipo "E inversa"hasTopping MozzarellaTopping specifica la classe di tutti gli individui che hanno almeno una relazione di tipo hasTopping con un individuo della classe MozzarellaTopping. Tale restrizione, hasTopping MozzarellaTopping, è costituita da quantificatore esistenziale che ha proprietà  hasTopping e filler MozzarellaTopping.

Questa restrizione descrive le classi di individui che hanno almeno un ingrediente di tipo mozzarella (ad esempio si escludono quantomeno la pizza marinara e quella ai frutti di mare).


Figura 16 - Esempio di restrizione esistenziale

La classe Pizza Margherita (MargheritaPizza) sarà  contraddistinta da due restrizioni esistenziali per specificare che ha ingredianti mozzarella (MozzarellaTopping) e pomodoro (TomatoTopping).

Basta quindi eseguire lo stesso procedimento fatto sopra anche per aggiungere questa volta la proprietà  hasTopping con filler TomatoTopping per specifiare che una MargheritaPizza ha quantomeno un TomatoTopping. In questo modo si ottiene che una pizza margherita ha come ingredienti mozzarella e pomodoro.

Individui

Per definire un individuo è necessario accedere al pannello Individuals attraverso la Barra dei Componenti di Protà©gà© (fig. 6 (3)). Il pannello è suddiviso in tre sezioni principali: la parte sinistra (Class Browser) mostra la gerarchia delle classi, la parte centrale (Instance Browser) mostra la lista (inizialmente vuota) degli individui appartenenti alla classe selezionata, la parte destra (Individual Editor) consente di caratterizzare l‘individuo selezionato nella lista centrale.

Reasoner

I reasoner (classificatori) sono programmi che offrono un insieme di servizi per "ragionare" (fare inferenza) sulle basi di conoscenza. Le ontologie realizzate in OWL-DL, in particolare, possono essere elaborate da reasoner basati sulla Logica Descrittiva, tra i quali si colloca quello di riferimento per gli esempi di questo articolo, Racer realizzato dall‘Università  di Amburgo [RACER].

Una volta installato e avviato, Racer attiva un server sulla porta di default HTTP 8080. L‘interfaccia HTTP di Racer supporta la connessione da parte di client conformi allo standard DIG [DIG] sviluppato dal DL Implementation Group e adottato da diversi software basati sulle logiche descrittive come Racer e FACT++. tra cui, appunto, Protà©gà©. Una volta in esecuzione, dunque, Racer può essere invocato da Protà©gà© attraverso HTTP, sfruttando lo standard DIG. La cosa è più semplice a farsi che a dirsi. Se Racer gira sulla stessa macchina di Protà©gà© e la porta HTTP è la 8080 (configurazione di default) Protegè è già  in grado di comunicare con Racer: per ogni esigenza è possibile personalizzare le impostazioni tramite il pannello di controllo raggiungibile dal menu OWL e poi navigando nella voce Preferences.

Figura 17 - Pannello Preferences di Protà©gà©

Dando "in pasto" al Reasoner un‘ontologia "costruita a mano" (asserted hierarchy/gerarchia dichiarata) consistente, si ottiene come ouput una gerarchia "inferita" dal ragionatore stesso (inferred hierarchy / gerarchia desunta). Precondizione quindi all‘ottenere una tassonomia inferita è avere una tassonomia definita "consistente" (ossia, "sensata", "coerente"). Una classe è detta consistente se possono esistere individui appartenenti ad essa. Se un‘ontologia ha delle classi inconsistenti, vuol dire che è stato fatto qualche errore in fase di definizione/modellazione dell‘ontologia e che quindi deve essere corretto. Per eseguire questo controllo di consistenza di un‘ontologia da Protà©gà© è sufficiente premere il pulsante Check Consistency sulla barra degli strumenti.


Figura 18 -Controllo di consistenza della gerarchia definita

In questo modo si avvia il controllo di consistenza dell‘ontologia da parte di Racer che la analizza e ne evidenzia eventuali classi inconsistenti. Provando ad effettuare il controllo di consistenza sull‘ontologia d‘esempio si ottiene che è consistente.

Per verificare la bontà  di questo controllo, si provi a creare una classe "sbagliata" facendola ereditare sia dalla classe Cane che dalla classe Gatto. Questo tipo di classe, il cui scopo è di verificare l‘integrità  dell‘ontologia, è chiamata anche classe Probe (sonda). Per ottenerla si seleziona la classe Cane e si crea una sottoclasse ProbeAnimaleInconsistente senza esplicitare alcuna disgiunzione. Dire che ProbeAnimaleInconsistente è sottoclasse sia di Cane che di Gatto equivale a dire che gli individui ProbeAnomaleInconsistente appartengono all‘intersezione tra Cane e Gatto: ma tale intersezione è vuota.

Figura 19 - Esempio di Inconsistenza

Si elimini ora la "classe sonda" ProbeAnimaleInconsistenteper ritornare ad avere una ontologia consistente. L‘operazione successiva è quella di fare generare a Racer una propria classificazione dell‘ontologia in modo automatico. Per ottenere una ontologia desunta (cioè inferita) dal reasoner a partire dall‘ontologia precedentemente definita "a mano", è necessario premere il pulsante Classify Taxonomy sulla barra degli strumenti (fig.9 (E)). Il risultato di questa operazione (detta anche classificazione di un‘Ontologia) è la visualizzazione delle due gerarchie con a destra la gerarchia dichiarata e a sinistra la gerarchia desunta dal reasoner. Se una classe è stata riclassificata a fronte di inferenze operate dal Reasoner il colore del nome della classe sarà  segnata in blu mentre, come già  detto, se una classe è inconsistente sarà  scritta e segnata in rosso.
Sfruttando le capacità  di inferenza offerte dal reasoner, a partire dalla stessa ontologia è possibile estrarre una quantità  maggiore di informazioni. Ciò che è implicito nelle condizioni delle classi nella gerarchia definita viene dedotto e reso esplicito dal reasoner nella gerarchia inferita. Ad esempio, riprendendo nuovamente in esame l‘esempio dell‘applicazione "Pizza Finder" [PIZZAF] la gerarchia delle pizze definite e desunte sono chiaramente diverse.

Figura 20 - Gerarchia definita & gerarchia desunta

Conclusioni

In questo articolo è stata data una panoramica degli elementi principali di OWL e di come questi possano essere trattati attraverso l‘editor Protà©gà© ed il reasoner Racer.

Riferimenti

[MOKA_SEMW_1] A. Rocca - S. Rossini, "Semantic Web- I parte: Introduzione a RDF, principi e Data Model", MokaByte 119, Giugno 2007

[MOKA_SEMW_2] A. Rocca - S. Rossini, "Semantic Web - II parte: RDFS e vocabolari controllati", MokaByte 120, Luglio/Agosto 2007

[WP_SW] Wikipedia Semantic Web
http://en.wikipedia.org/wiki/Semantic_web

[WP_OWL] Web Ontology Language
http://en.wikipedia.org/wiki/Web_Ontology_Language

[WP_ONT] Ontologia
http://it.wikipedia.org/wiki/Ontologia_%28informatica%29

[WK_INF] Inferenza
http://it.wikipedia.org/wiki/Inferenza

[W3CSW] W3C Semantic Web
http://www.w3.org/2001/sw/

[PROTÃ?GÃ?] Protà©gà©
http://protege.stanford.edu/

[TUTP] A Practical Guide To Building OWL Ontologies Using TheProtà©gà©-OWL Plugin and CO-ODE Tools
http://www.co-ode.org/resources/tutorials/ProtegeOWLTutorial.pdf

[DIG] DIG Interface
http://dig.sourceforge.net

[RACER] Racer
http://www.sts.tu-harburg.de/~r.f.moeller/racer/

[FaCT++] FaCT OWL-DL reasoner
http://owl.man.ac.uk/factplusplus/

[COODE] CO-ODE website
http://www.co-ode.org/

[PIZZAF] The Pizza Finder Application
http://www.co-ode.org/downloads/pizzafinder/

[COPO]
http://www.co-ode.org/ontologies/pizza/pizza_20041007.owl

[W3C_OWL]
http://www.w3.org/TR/owl-features/

[SWED] The Semantic Web Environmental Directory
http://www.swed.org.uk/swed/index.html

Condividi

Pubblicato nel numero
121 settembre 2007
Stefano Rossini è nato a Giussano (MI) il 29/10/1970 e ha conseguito il diploma universitario in Ingegneria Informatica presso il Politecnico di Torino. Ha maturato più di venti anni di esperienza in diversi progetti Enterprise mission-critical ricoprendo i ruoli di IT Program Manager, Project Manager & Software Architect presso importanti…
Articoli nella stessa serie
Ti potrebbe interessare anche