Java 開發人員幸運地擁有 Jena 這套優秀的 RDF 框架,提供讀寫 RDF 的 API,支援多種持久化方式。Jena 設計目標是良好處理 RDF 資料模型,如同 JDBC 適合關聯模型。資料庫應用大量程式碼用於保存 Java 物件與從資料庫聚合物件;語義 Web 應用面臨相同問題:必須實現 Java 物件與 RDF 相互轉換。開發者需編寫大量程式碼消除領域模型(通常為 JavaBeans)與 Jena 以 RDF 為中心的 API 間差異。
本文展示 Jenabean 的 Java-to-RDF 綁定框架如何簡化流程並減少程式碼。您將檢視 Jena 客戶端程式碼並與 Jenabean 基於 JavaBean 的程式設計模型對比。
以簡單 RDF 範例(N3 格式)說明:
<https://www.ibm.com/developerworks/xml/library/j-jena/>
a dc:Article ;
dc:creator "Philip McCarthy"^^xsd:string ;
dc:subject "jena, rdf, java, semantic web"^^xsd:string ;
dc:title "Introduction to Jena"^^xsd:string .
說明「Jena 簡介」一文由 Philip McCarthy 撰寫,主題含 jena、rdf、java、semantic web。詞彙為 Dublin Core 元資料一部分。
String NS = "https://purl.org/dc/elements/1.1/";
OntModel m = createModel();
OntClass articleCls = m.createClass(NS + "Article");
Individual i = articleCls.createIndividual(
"https://www.ibm.com/developerworks/xml/library/j-jena/");
Property title = m.getProperty(NS + "title");
Literal l = m.createTypedLiteral("Introduction to Jena");
i.setPropertyValue(title, l);
Property creator = m.getProperty(NS + "creator");
l = m.createTypedLiteral("Philip McCarthy");
i.setPropertyValue(creator, l);
Property subject = m.getProperty(NS + "subject");
l = m.createTypedLiteral("jena, rdf, java, semantic web");
i.setPropertyValue(subject, l);
m.write(System.out, "N3");
每個數值斷言需三行程式碼:存取屬性、建立字面值、斷言屬性關係。優點是透明、直接對應 RDF 概念,類似 JDBC 直接對應關聯模型。
Model m = ModelFactory.createOntologyModel();
Bean2RDF writer = new Bean2RDF(m);
Article article = new Article("https://www.ibm.com/developerworks/xml/library/j-jena/");
article.setCreator("Philip McCarthy");
article.setTitle("Introduction to Jena");
article.setSubject("jena, rdf, java, semantic web");
writer.save(article);
m.write(System.out, "N3");
差異明顯:Jenabean 產生對多數 Java 開發者熟悉的程式碼。Bean2RDF 轉換器讓你只需呼叫 JavaBean 的 setter 方法。
Jenabean 主要優勢是填補 Java 物件與 RDF 間鴻溝,讓你用熟悉的 OOP 風格編寫語義 Web 應用。但 Java 物件與 RDF 資料表示方式不同,好的綁定工具必須解決三問題:
Jenabean 解決上述三問題,同時保持簡單:無需程式碼生成、位元碼生成或即時位元碼處理庫,僅需 Jena 及其庫。預設使用保守策略保存物件及其直接屬性(淺層模式)。開發者必須明確指示才進行「深度」複製,或指定要保存/載入的特定集合屬性。
Jenabean 使用 Java 註解聲明 Bean 如何映射到 RDF。當模型由 Java 物件驅動時最有用。
同 JPA/Hibernate,需確保物件有唯一 ID。Jenabean 需在至少一個 Bean 欄位加入 @Id 註解作為唯一識別碼:
package example;
import thewebsemantic.Id;
public class Person {
private String email;
@Id
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
@Id 為 Jenabean 提供足夠資訊可靠保存/載入 Person 實例。電子郵件地址唯一,為有效 ID。保存範例:
Model m = ModelFactory.createOntologyModel();
Bean2RDF writer = new Bean2RDF(m);
Person p = new Person();
p.setEmail("person@example.com");
writer.save(p);
m.write(System.out, "N3");
...
<https://example/Person>
a owl:Class ;
<https://thewebsemantic.com/javaclass> "example.Person" .
<https://example/Person/taylor_cowan@yahoo.com>
a <https://example/Person> ;
<https://example/email> "taylor_cowan@yahoo.com"^^xsd:string .
Bean2RDF 預設淺層模式,保存實例與單一屬性。若 Person 類別未加入模型,斷言新類別為 owl:Class 實例。Jenabean 使用套件名作為本體類別命名空間。第二個斷言為註解,指明建立個體的 Java 類別。Person 實例與電子郵件皆被斷言。Jenabean 先為已保存實例建立 URI,處理 email 屬性並斷言為字串字面值。
RDF 個體需 URI,Java 開發者傾向用唯一 ID。Jenabean 將宣告的 ID 欄位附加到命名空間(預設來自套件與類別名)協助建立 URI。建立 URI 後,使用 RDF2Bean 從模型載入:
RDF2Bean reader = new RDF2Bean(m);
Person p2 = reader.load(Person.class, "person@example.com");
Collection<Person> people = reader.load(Person.class);
Jenabean 也支援綁定到 SPARQL 查詢結果。總結:Bean 作者至少指明哪個欄位值對所有實例唯一。保存後,根據類別套件與名稱為類別與屬性提供預設 URI,讓你從 Java 層輕鬆快速建立 RDF。
使用 @Namespace 註解將 Bean 映射到特定命名空間:
@Namespace("https://jenabean.googlecode.com/")
public class Person { ... }
新命名空間用於類別及其屬性(而非預設套件)。
語義 Web 需通用屬性使資料具更多語義。FOAF(Friend of a Friend)詞彙為電子郵件提供 foaf:mbox 屬性。使用 @RdfProperty 註解:
@Id
@RdfProperty("https://xmlns.com/foaf/0.1/mbox")
public String getEmail() { return email; }
email 屬性現斷言為 foaf:mbox,可被其他 RDF 代理理解為電子郵件地址。
OWL/RDF 中透過同一屬性多重斷言表達各種基數關係。Jenabean 透過 java.util.Collection 介面大幅簡化。擴充 Person 支援朋友關係(使用 foaf:knows):
public Collection<Person> friends = new LinkedList<Person>();
@RdfProperty("https://xmlns.com/foaf/0.1/knows")
public Collection<Person> getFriends() { return friends; }
public void setFriends(Collection<Person> friends) { this.friends = friends; }
建立 Person 與多個朋友,將朋友加入 friends 集合實現關聯。@RdfProperty 可選,但綁定第三方詞彙時重要。保存後模型包含遵守 FOAF 規範的新資料。
RDF 未定義子節點順序,無法假設 Jena 以特定順序檢索朋友列表。若需有序列表,Jenabean 將 Java 陣列映射到 RDF 序列。為 Person 提供一組電話號碼(String 陣列):
private String[] phoneNumbers;
public String[] getPhoneNumbers() { return phoneNumbers; }
public void setPhoneNumbers(String[] phoneNumbers) { this.phoneNumbers = phoneNumbers; }
生成 RDF 使用 rdf:Seq 與 rdf:_1、rdf:_2 等有序屬性。
Jenabean 協助你用熟悉的 JavaBean 模型讀寫 RDF。本文闡述基本原理:建立、保存、讀取簡單 Bean。這只是用 Java 編寫語義 Web 應用的一小部分。請訪問 Jenabean 專案主頁了解更多、提供回饋或尋求協助。
來源:https://www.ibm.com/developerworks/cn/java/j-jenabean.html