資源John Smith在圖中用橢圓表示, 并被一個(gè)統(tǒng)一資源定位符(URI)所標(biāo)識(shí), 在本例中是"http://.../JohnSmith"). 如果你想要通過(guò)你的瀏覽器來(lái)訪(fǎng)問(wèn)這個(gè)資源的話(huà),你很有可能會(huì)失敗. 四月的愚人節(jié)笑話(huà)并不經(jīng)得起考驗(yàn), 相反如果你的瀏覽器把John Smith傳遞到你的桌面的話(huà), 你才該感到驚訝. 如果你并不熟悉URI's的話(huà), 你可以把它們想象成簡(jiǎn)單的陌生名字.
資源擁有屬性(property). 在這些例子中, 我們對(duì)John Smith名片上出現(xiàn)的那些屬性很感興趣.圖1只顯示了一個(gè)屬性, John Smith的全名. 屬性是由標(biāo)有屬性名的箭頭表示的. 屬性的名字也是一個(gè)URI, 但是由于URI十分冗長(zhǎng)笨重, 所以圖中將它顯示為XML qname的形式. 在':'之前的部分稱(chēng)為命名空間前綴并表示了一個(gè)命名空間. 在':'之后的部分稱(chēng)為局部名, 并表示在命名空間中的一個(gè)名字. 在寫(xiě)成RDF XML形式時(shí), 屬性常常以qname的形式表示, 這是一個(gè)在圖形和文本中的簡(jiǎn)單的縮寫(xiě)方法. 然而, 嚴(yán)格地講, 屬性應(yīng)該用URI來(lái)標(biāo)識(shí). 命名空間前綴:局部名的形式是一種命名空間連接局部名的URI縮寫(xiě). 當(dāng)瀏覽器訪(fǎng)問(wèn)時(shí), 用并沒(méi)有強(qiáng)制屬性的URI必須指向一些具體的事物.
每個(gè)屬性都有一個(gè)值. 在此例中, 值為一個(gè)文本(literal), 我們現(xiàn)在可以把它看成一個(gè)字符串.文本在圖中顯示為長(zhǎng)方形.
Jena是一個(gè)Java API, 我們可以用它來(lái)創(chuàng)建和操縱諸如上述例圖的RDF圖. Jena設(shè)有表示圖(graph), 資源(resource), 屬性和文本(literal)的對(duì)象類(lèi). 表示資源, 屬性和文本的接口分別稱(chēng)為Resource, Property, 和Literal. 在Jena中, 一個(gè)圖(graph)被稱(chēng)為一個(gè)模型并被Model接口所表示.
創(chuàng)建上述例圖或稱(chēng)為上述模型的代碼很簡(jiǎn)單:
// some definitions
static String personURI = "http://somewhere/JohnSmith";
static String fullName = "John Smith";
// create an empty Model
Model model = ModelFactory.createDefaultModel();
// create the resource
Resource johnSmith = model.createResource(personURI);
// add the property
johnSmith.addProperty(VCARD.FN, fullName);
這些代碼先定義了一些常量, 然后使用了ModelFactory類(lèi)中的createDefaultMode()方法創(chuàng)建了一個(gè)空的基于內(nèi)存存儲(chǔ)的模型(Model 或 model). Jena還包含了Model接口的其他實(shí)現(xiàn)方式. 例如, 使用關(guān)系數(shù)據(jù)庫(kù)的, 這些類(lèi)型 Model接口也可以從ModelFactory中創(chuàng)建.
于是John Smith這個(gè)資源就被創(chuàng)建了, 并向其添加了一個(gè)屬性. 此屬性由一個(gè)"常" ("constant")類(lèi)VCARD提供, 這個(gè)類(lèi)保存了在VCARD模式(schema)中所有定義的表示對(duì)象. Jena也為其他一些著名的模式提供了常類(lèi)的表示方法, 例如是RDF和RDF模式, Dublin 核心標(biāo)準(zhǔn)和DAML.
創(chuàng)建資源和添加屬性的代碼可以寫(xiě)成更緊湊的層疊形式:
Resource johnSmith =
model.createResource(personURI)
.addProperty(VCARD.FN, fullName);
這個(gè)例子的工作代碼可以在Jena發(fā)布的材料的教程包中的Tutorial1中找到. 作為練習(xí), 你自己可以獲得此代碼并修改其以創(chuàng)建一個(gè)簡(jiǎn)單VCARD.
現(xiàn)在讓我們?yōu)関card再增加一些更詳細(xì)的內(nèi)容, 以便探索更多的RDF和Jena的特性.
在第一個(gè)例子里, 屬性值為一個(gè)文本. 然而RDF屬性也可以采用其他的資源作為其屬性值. 下面這個(gè)例子使用常用的RDF技術(shù)展示了如何表示John Smith名字的不同部分:
在這里我們?cè)黾恿艘粋€(gè)新的屬性, vcard:N, 來(lái)表示John Smith名字的結(jié)構(gòu). 這個(gè)模型有幾點(diǎn)有趣之處. 注意屬性vcard:N使用一個(gè)資源作為起屬性值. 同時(shí)注意代表復(fù)合名字的橢圓并沒(méi)有URI標(biāo)識(shí). 它被認(rèn)為是一個(gè)空白結(jié)點(diǎn)(blank Node).
創(chuàng)建此例的Jena代碼也十分簡(jiǎn)單. 首先是一些聲明和對(duì)空模型的創(chuàng)建.
// some definitions
String personURI = "http://somewhere/JohnSmith";
String givenName = "John";
String familyName = "Smith";
String fullName = givenName + " " + familyName;
// create an empty Model
Model model = ModelFactory.createDefaultModel();
// create the resource
// and add the properties cascading style
Resource johnSmith
= model.createResource(personURI)
.addProperty(VCARD.FN, fullName)
.addProperty(VCARD.N,
model.createResource()
.addProperty(VCARD.Given, givenName)
.addProperty(VCARD.Family, familyName));
此例的工作代碼可以在Jena發(fā)布材料的教程包的Tutorial2中得到.
________________________________________
陳述
RDF模型中的每一個(gè)箭頭表示為一個(gè)陳述(statement). 每一個(gè)陳述聲明了關(guān)于某個(gè)資源的某個(gè)事實(shí). 一個(gè)陳述有三部分組成.
主體, 也就是箭頭的出發(fā)的資源.
謂詞, 也就是標(biāo)識(shí)箭頭的屬性.
客體, 也就是箭頭所指向的那個(gè)資源或文本.
一個(gè)陳述有時(shí)也叫做一個(gè)三元組的原因就是它由三部分組成.
一個(gè)RDF模型(譯者注: 指Jena中的接口Model)是由一組陳述所組成的. 在Tutorial2中, 每調(diào)用一次addProperty函數(shù)就會(huì)在模型中增加另一個(gè)陳述. (因?yàn)橐粋€(gè)模型是由一組陳述組成的, 所以增加一個(gè)重復(fù)的陳述并不會(huì)產(chǎn)生任何意義.) Jena模型接口定義了一個(gè)listStatements()方法, 此方法會(huì)返回一個(gè)StmtIterator類(lèi)型的變量. StmtIterator是Java中Iterator的一個(gè)子類(lèi)型, 這個(gè)StmtIterator變量重復(fù)迭代了該接口模型中的所有陳述. StmtIterator類(lèi)型中有一個(gè)方法nextStatement(), 該方法會(huì)從iterator返回下一個(gè)陳述. (就和next()返回的一樣, 但是已將其映射為Statement類(lèi)型). 接口Statement提供了訪(fǎng)問(wèn)陳述中主體, 謂詞和客體的方法.
現(xiàn)在我們會(huì)用使用那個(gè)接口來(lái)擴(kuò)展Tutorial2, 使起列出所有的創(chuàng)建的陳述并將它們打印出來(lái). 此例完整的代碼可以在Tutorial3中找到.
// list the statements in the Model
StmtIterator iter = model.listStatements();
// print out the predicate, subject and object of each statement
while (iter.hasNext()) {
Statement stmt = iter.nextStatement(); // get next statement
Resource subject = stmt.getSubject(); // get the subject
Property predicate = stmt.getPredicate(); // get the predicate
RDFNode object = stmt.getObject(); // get the object
System.out.print(subject.toString());
System.out.print(" " + predicate.toString() + " ");
if (object instanceof Resource) {
System.out.print(object.toString());
} else {
// object is a literal
System.out.print(" \"" + object.toString() + "\"");
}
System.out.println(" .");
}
因?yàn)橐粋€(gè)陳述的客體可以是一個(gè)資源也可以是一個(gè)文本. getObject()方法會(huì)返回一個(gè)類(lèi)型為RDFNode的客體, RDFNode是Resource和Literal類(lèi)共同的超類(lèi). 為了確定本例中的客體確切的類(lèi)型, 代碼中使用 instanceof來(lái)確定其類(lèi)型和相應(yīng)的處理.
運(yùn)行后, 此程序回產(chǎn)生與此相似的輸出:
http://somewhere/JohnSmith http://www.w3.org/2001/vcard-rdf/3.0#N anon:14df86:ecc3dee17b:-7fff.
anon:14df86:ecc3dee17b:-7fff http://www.w3.org/2001/vcard-rdf/3.0#Family "Smith".
anon:14df86:ecc3dee17b:-7fff http://www.w3.org/2001/vcard-rdf/3.0#Given "John" .
http://somewhere/JohnSmith http://www.w3.org/2001/vcard-rdf/3.0#FN "John Smith".
現(xiàn)在你明白了為什么模型構(gòu)建會(huì)更加清晰. 如果你仔細(xì)觀察, 就會(huì)發(fā)現(xiàn)上面每一行都由三個(gè)域組成, 這三個(gè)域分別代表了每一個(gè)陳述的主體, 謂詞和客體. 在此模型中有四個(gè)箭頭, 所以會(huì)有四個(gè)陳述. "anon:14df86:ecc3dee17b:-7fff"是有Jena產(chǎn)生的一個(gè)內(nèi)部標(biāo)識(shí)符, 它不是一個(gè)URI, 也不應(yīng)該與URI混淆. 它只是Jena處理時(shí)使用的一個(gè)內(nèi)部標(biāo)號(hào). 寫(xiě)RDF 應(yīng)該有類(lèi)似的輸出: W3C的RDF規(guī)格說(shuō)明書(shū)規(guī)定了如何用 XML的形式來(lái)表示RDF. RDF XML的語(yǔ)法十分復(fù)雜. 讀者可以在RDF核心工作小組制定的RDF入門(mén)篇(primer)中找到更詳細(xì)的指導(dǎo). 但是不管怎么樣, 讓我們先迅速看一下應(yīng)該如何解釋上面的RDF XML輸出 此writer, 也就是所謂的PrettyWriter, 利用RDF/XML縮寫(xiě)語(yǔ)法把模型寫(xiě)地更為緊湊. 它也能保存盡可能保留空白結(jié)點(diǎn). 然而, 它并不合適來(lái)輸出大的模型. 因?yàn)樗男阅懿豢赡鼙蝗藗兯邮? 要輸出大的文件和保留空白結(jié)點(diǎn), 可以用N-三元組的形式輸出: 這會(huì)產(chǎn)生類(lèi)似于Tutorial3的輸出, 此輸出會(huì)遵循N-三元組的規(guī)格. ________________________________________ // create an empty model // use the class loader to find the input file // read the RDF/XML file // write it to standard out ________________________________________ ________________________________________ 一般而言, 一個(gè)陳述的客體可以是一個(gè)資源或是一個(gè)文本. 所以此應(yīng)用程序代碼知道這個(gè)值一定是個(gè)資源, 就將類(lèi)型資源映射到返回的對(duì)象上. Jena的目標(biāo)之一是提供會(huì)返回值為特定類(lèi)型的方法, 這樣,應(yīng)用程序就不必再做類(lèi)型轉(zhuǎn)換工作, 也不必再編譯時(shí)做類(lèi)型檢查工作. 以上的代碼片段也可以寫(xiě)成更方便的形式: 在這個(gè)例子中, 資源vcard只有一個(gè)vcard:FN屬性和一個(gè)vcard:N屬性. RDF允許資源有重復(fù)的屬性, 例如Adam可能有超過(guò)一個(gè)的昵稱(chēng). 讓我們假設(shè)他有兩個(gè)昵稱(chēng): 正如前面所提到的那樣, Jena將RDF模型表示為一組陳述, 所以在模型中新增一個(gè)與原有陳述有著相同的主體,謂詞和客體的陳述并不會(huì)后什么作用. Jena沒(méi)有定義會(huì)返回模型中存在的兩個(gè)昵稱(chēng)中的哪一個(gè). Vcard.getProperty(VCARD.NICKNAME)調(diào)用的結(jié)果是不確定的. Jena會(huì)返回這些值中的某一個(gè), 但是并不保證兩次連續(xù)的調(diào)用會(huì)同一個(gè)值. 查詢(xún)模型 然而, 不幸的是, 我們現(xiàn)在正在使用的vcard模式并沒(méi)有為vcard定義類(lèi)型. 然而, 如果我們假設(shè)只有類(lèi)型為vcard的資源才會(huì)使用vcard:FN屬性, 并且在我們的數(shù)據(jù)中, 所有此類(lèi)資源都有這樣一個(gè)屬性, 那么我們就可以像這樣找到所有的vcard: 所有的這些查詢(xún)方法不過(guò)是在原語(yǔ)查詢(xún)方法model.listStatements(Select s)上稍做變化而已. 此方法會(huì)返回一個(gè)iterator, 該iterator會(huì)跌代模型中所有被s選中的陳述. 這個(gè)selector接口被設(shè)計(jì)成可擴(kuò)展的, 但是目前, 它只有一個(gè)執(zhí)行類(lèi),那就是com.hp.hpl.jena.rdf.model包中的SimpleSelector類(lèi). 在Jena中使用SimpleSelector是很少見(jiàn)的情況, 即當(dāng)需要直接使用一個(gè)特定類(lèi)而不是使用接口. SimpleSelector的構(gòu)造函數(shù)帶有三個(gè)參數(shù): Selector selector = new SimpleSelector(subject, predicate, object) 這個(gè)示例使用了一個(gè)簡(jiǎn)潔的Java技術(shù), 就是當(dāng)創(chuàng)建此類(lèi)的一個(gè)實(shí)例時(shí)重載一個(gè)內(nèi)聯(lián)的方法. 這里selects(…)方法會(huì)檢查以保證全名以"Smith"做結(jié)尾. 重要的是要注意對(duì)主體, 謂語(yǔ)和客體的過(guò)濾是在調(diào)用selects(…)方法之前的執(zhí)行的, 所以額外的測(cè)試只會(huì)被應(yīng)用于匹配的陳述. 雖然在功能上它們可能是等同的, 但是第一種形式會(huì)列舉出模型中所有的陳述, 然后再對(duì)它們進(jìn)行逐一的測(cè)試. 而第二種形式則允許執(zhí)行時(shí)建立索引來(lái)提供性能. 你可以在一個(gè)大模型中自己試試驗(yàn)證一下, 但是現(xiàn)在先為自己倒一杯咖啡休息一下吧. and 讓我們看一下這個(gè)代碼的功能(完整的代碼在Tutorial9中), 再看看會(huì)發(fā)生什么. // merge the Models // print the Model as RDF/XML petty writer會(huì)產(chǎn)生如下的輸出:
W3C的RDF核心工作小組定義了一個(gè)類(lèi)似的表示符號(hào)稱(chēng)為N-三元組(N-Triples). 這個(gè)名字表示會(huì)使用"三元組符號(hào)". 在下一節(jié)中我們會(huì)看到Jena有一個(gè)內(nèi)置的N-三元組寫(xiě)機(jī)制(writer).
Jena設(shè)有讀寫(xiě)XML形式的RDF方法. 這些方法可以被用來(lái)將一個(gè)RDF模型保存到文件并在日后重新將其讀回.
Tutorial3創(chuàng)建了一個(gè)模型并將其以三元組的形式輸出. Tutorial4對(duì)Tutorial3做了修改, 使其將此模型以RDF XML的形式輸出到標(biāo)準(zhǔn)輸出流中. 這個(gè)代碼依然十分簡(jiǎn)單: model.write可以帶一個(gè)OutputStream的參數(shù).
// now write the model in XML form to a file
model.write(System.out);
<rdf:RDF
xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'//命名空間
xmlns:vcard='http://www.w3.org/2001/vcard-rdf/3.0#'
>
<rdf:Description rdf:about='http://somewhere/JohnSmith'>
<vcard:FN>John Smith</vcard:FN>
<vcard:N rdf:nodeID="A0"/>
</rdf:Description>
<rdf:Description rdf:nodeID="A0">
<vcard:Given>John</vcard:Given>
<vcard:Family>Smith</vcard:Family>
</rdf:Description>
</rdf:RDF>
RDF常常嵌入在一個(gè)<rdf:RDF>元素中. 如果有其他的方法知道此XML是RDF的話(huà),該元素是可以不寫(xiě)的. 然而我們常常會(huì)使用它. 在這個(gè)RDF元素中定義了兩個(gè)在本文檔中使用的命名空間. 接下來(lái)是一個(gè)<rdf:Description>元素, 此元素描述了URI為"http://somewhere/JohnSmith"的資源. 如果其中的rdf:about屬性被省略的話(huà), 這個(gè)元素就表示一個(gè)空白結(jié)點(diǎn).
<vcard:FN>元素描述了此資源的一個(gè)屬性. 屬性的名字"FN"是屬于vcard命名空間的. RDF會(huì)通過(guò)連接命名空間前綴的URI和名字局部名"FN"來(lái)形成該資源的URI "http://www.w3.org/2001/vcard-rdf/3.0#FN". 這個(gè)屬性的值為文本"John Smith".
<vcard:N>元素是一個(gè)資源. 在此例中, 這個(gè)資源是用一個(gè)相對(duì)URI來(lái)表示的. RDF會(huì)通過(guò)連接這個(gè)相對(duì)URI和此文檔的基準(zhǔn)URI來(lái)把它轉(zhuǎn)換為一個(gè)絕對(duì)URI.
但是, 在這個(gè)RDF XML輸出中有一個(gè)錯(cuò)誤, 它并沒(méi)有準(zhǔn)確地表示我們所創(chuàng)建的模型. 模型中的空白結(jié)點(diǎn)被分配了一個(gè)URI. 它不再是空白的了. RDF/XML語(yǔ)法并不能表示所有的RDF模型. 例如它不能表示一個(gè)同時(shí)是兩個(gè)陳述的客體的空白結(jié)點(diǎn). 我們用來(lái)寫(xiě)這個(gè)RDF/XML的'啞'writer方法并沒(méi)有試圖去正確的書(shū)寫(xiě)這個(gè)模型的子集, 雖然其原本可以被正確書(shū)寫(xiě). 它給每一個(gè)空白結(jié)點(diǎn)一個(gè)URI, 使其不再空白.
Jena有一個(gè)擴(kuò)展的接口, 它允許新的為不同的RDF串行化語(yǔ)言設(shè)計(jì)的writer可以被輕易地插入. 以上的調(diào)用會(huì)激發(fā)一個(gè)標(biāo)準(zhǔn)的'啞'writer方法. Jena也包含了一個(gè)更加復(fù)雜的RDF/XML writer, 它可以被用攜帶另一個(gè)參數(shù)的write()方法所調(diào)用.
// now write the model in XML form to a file
model.write(System.out, "RDF/XML-ABBREV");
// now write the model in XML form to a file
model.write(System.out, "N-TRIPLE");
讀RDF
Tutorial 5 演示了如何將用RDF XML記錄的陳述讀入一個(gè)模型. 在此例中, 我們提供了一個(gè)小型RDF/XML形式的vcard的數(shù)據(jù)庫(kù). 下面代碼會(huì)將其讀入和寫(xiě)出. 注意: 如果要運(yùn)行這個(gè)小程序, 應(yīng)該把輸入文件放在你的classpath所指向的目錄或jar中.
Model model = ModelFactory.createDefaultModel();
InputStream in = Tutorial05.class
.getClassLoader()
.getResourceAsStream(inputFileName);
if (in == null) {
throw new IllegalArgumentException(
"File: " + inputFileName + " not found");
}
model.read(new InputStreamReader(in), "");
model.write(System.out);
read()方法中的第二個(gè)參數(shù)是一個(gè)URI, 它是被用來(lái)解決相對(duì)URI的. 因?yàn)樵跍y(cè)試文件中沒(méi)有使用相對(duì)URI, 所以它允許被置為空值. 運(yùn)行時(shí), Tutorial5會(huì)產(chǎn)生類(lèi)似如下的XML輸出
<rdf:RDF
xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
xmlns:vcard='http://www.w3.org/2001/vcard-rdf/3.0#'
>
<rdf:Description rdf:nodeID="A0">
<vcard:Family>Smith</vcard:Family>
<vcard:Given>John</vcard:Given>
</rdf:Description>
<rdf:Description rdf:about='http://somewhere/JohnSmith/'>
<vcard:FN>John Smith</vcard:FN>
<vcard:N rdf:nodeID="A0"/>
</rdf:Description>
<rdf:Description rdf:about='http://somewhere/SarahJones/'>
<vcard:FN>Sarah Jones</vcard:FN>
<vcard:N rdf:nodeID="A1"/>
</rdf:Description>
<rdf:Description rdf:about='http://somewhere/MattJones/'>
<vcard:FN>Matt Jones</vcard:FN>
<vcard:N rdf:nodeID="A2"/>
</rdf:Description>
<rdf:Description rdf:nodeID="A3">
<vcard:Family>Smith</vcard:Family>
<vcard:Given>Rebecca</vcard:Given>
</rdf:Description>
<rdf:Description rdf:nodeID="A1">
<vcard:Family>Jones</vcard:Family>
<vcard:Given>Sarah</vcard:Given>
</rdf:Description>
<rdf:Description rdf:nodeID="A2">
<vcard:Family>Jones</vcard:Family>
<vcard:Given>Matthew</vcard:Given>
</rdf:Description>
<rdf:Description rdf:about='http://somewhere/RebeccaSmith/'>
<vcard:FN>Becky Smith</vcard:FN>
<vcard:N rdf:nodeID="A3"/>
</rdf:Description>
</rdf:RDF>
Jena RDF 包
Jena是一個(gè)為語(yǔ)義網(wǎng)應(yīng)用設(shè)計(jì)的一個(gè)Java API. 對(duì)應(yīng)用開(kāi)發(fā)者而言, 主要可用的RDF包是com.hp.hpl.jena.rdf.model. 因?yàn)锳PI是以接口的方式定義的, 所以應(yīng)用代碼可以使用不同的實(shí)現(xiàn)機(jī)制而不用改變代碼本身. 這個(gè)包包含了可以表示模型, 資源, 屬性, 文本, 陳述和其他RDF關(guān)鍵概念的接口, 還有一個(gè)用來(lái)創(chuàng)建模型的ModelFactory. 所以如果要應(yīng)用代碼與實(shí)現(xiàn)類(lèi)保持獨(dú)立, 最好盡可能地使用接口, 而不要使用特定的實(shí)現(xiàn)類(lèi).
com.hp.hpl.jena.Tutorial包包含了本教程所有例子中使用到的工作源代碼.
com.hp.hpl.jena.impl這些包包含了許多執(zhí)行時(shí)所常用的執(zhí)行類(lèi). 比如, 它們定義了諸如ResourseImpl, PropertyImpl和LiteralImpl的類(lèi), 這些類(lèi)可以被不同的應(yīng)用直接使用也可以被繼承使用. 應(yīng)用程序應(yīng)該盡可能少地直接使用這些類(lèi). 例如, 與其使用ResouceImpl來(lái)創(chuàng)建一個(gè)新的實(shí)例, 更好的辦法是使用任何正在使用的模型的createResource方法來(lái)完成. 那樣的話(huà), 如果模型的執(zhí)行采用了一個(gè)優(yōu)化的Resouce執(zhí)行, 那么在這兩種類(lèi)型中不需要有任何的轉(zhuǎn)換工作.
操縱模型
到目前為止, 本教程主要講述的是如何創(chuàng)建, 讀入和輸出RDF模型. 現(xiàn)在是時(shí)候要講述如何訪(fǎng)問(wèn)模型中的信息.
如果有了一個(gè)資源的URI, 那么就可以用Model.getResource(String uri)來(lái)從模型獲取這個(gè)資源對(duì)象. 這個(gè)方法被定義來(lái)返回一個(gè)資源對(duì)象, 如果它確實(shí)存在于模型中, 否則的話(huà)就創(chuàng)建一個(gè)新的. 例如, 如何從模型中獲取Adam Smith資源, 這個(gè)模型是Tutorial5中從文件讀入的:
// retrieve the John Smith vcard resource from the model
Resource vcard = model.getResource(johnSmithURI);
Resouce接口定義了一系列用于訪(fǎng)問(wèn)某個(gè)資源的屬性的方法. Resource.getProperty(Property p)方法訪(fǎng)問(wèn)了該資源的屬性. 這個(gè)方法不允許通常的Java訪(fǎng)問(wèn)的轉(zhuǎn)換, 因?yàn)樗祷氐膶?duì)象是Statement, 而不是你所預(yù)計(jì)的Property. 返回整個(gè)陳述的好處是允許應(yīng)用程序通過(guò)使用它的某個(gè)訪(fǎng)問(wèn)方法來(lái)訪(fǎng)問(wèn)該陳述的客體來(lái)訪(fǎng)問(wèn)這個(gè)屬性值. 例如如何獲取作為vcard:N屬性值的資源:
// retrieve the value of the N property
Resource name = (Resource) vcard.getProperty(VCARD.N)
.getObject();
// retrieve the value of the FN property
Resource name = vcard.getProperty(VCARD.N)
.getResource();
類(lèi)似地, 屬性的文本值也可以被獲取:
// retrieve the given name property
String fullName = vcard.getProperty(VCARD.FN)
.getString();
// add two nickname properties to vcard
vcard.addProperty(VCARD.NICKNAME, "Smithy")
.addProperty(VCARD.NICKNAME, "Adman");
一個(gè)屬性很有可能會(huì)出現(xiàn)多次, 而方法Resource.listProperty(Property p)可以用來(lái)返回一個(gè)iterator, 這個(gè)iterator會(huì)列出所有的值. 此方法所返回的iterator返回的對(duì)象的類(lèi)型為Statement.我們可以像這樣列出所有的昵稱(chēng):
// set up the output
System.out.println("The nicknames of \""
+ fullName + "\" are:");
// list the nicknames
StmtIterator iter = vcard.listProperties(VCARD.NICKNAME);
while (iter.hasNext()) {
System.out.println(" " + iter.nextStatement()
.getObject()
.toString());
}
The nicknames of "John Smith" are:
Smithy
Adman
一個(gè)資源的所有屬性可以用不帶參數(shù)的listStatement()方法列出.
前一節(jié)討論了如何通過(guò)一個(gè)有著已知URI的資源來(lái)操縱模型. 本節(jié)要討論查詢(xún)模型. 核心的Jena API只支持一些有限的查詢(xún)?cè)Z(yǔ). 對(duì)于更強(qiáng)大查詢(xún)?cè)O(shè)備RDQL的介紹不在此文檔中.
列出模型所有陳述的Model.listStatements()方法也許是最原始的查詢(xún)模型方式. 然而并不推薦在大型的模型上使用這個(gè)方法. 類(lèi)似的有Model.listSubjects(), 但其所返回的iterator會(huì)迭代所有含有屬性的資源, 例如是一些陳述的主體.
Model.listSubjectsWithProperty(Property p, RDFNode o)方法所返回的iterator跌代了所有具有屬性p且p屬性的值為o的資源. 我們可能會(huì)預(yù)計(jì)使用rdf:type屬性來(lái)搜索資源的類(lèi)型屬性以獲得所有的vcard資源:
// retrieve all resource of type Vcard.
ResIterator iter = model.listSubjectsWithProperty(RDF.type, VCARD.Vcard);
// list vcards
ResIterator iter = model.listSubjectsWithProperty(VCARD.FN);
while (iter.hasNext()) {
Resource r = iter.nextResource();
...
}
這個(gè)selector會(huì)選擇所有主體與參數(shù)subject相配, 謂詞與參數(shù)predicate相配, 且客體與參數(shù)object相配的陳述.
如果某個(gè)參數(shù)值為null, 則它表示與任何值均匹配; 否則的話(huà), 它們就會(huì)匹配一樣的資源或文本. (當(dāng)兩個(gè)資源有相同的URI或是同一個(gè)空白結(jié)點(diǎn)時(shí), 這兩個(gè)資源就是一樣的; 當(dāng)兩個(gè)文本是一樣的當(dāng)且僅當(dāng)它們的所有成分都是一樣的.) 所以:
Selector selector = new SimpleSelector(null, null, null);
會(huì)選擇模型中所有的陳述.
Selector selector = new SimpleSelector(null, VCARD.FN, null);
會(huì)選擇所有謂詞為VCARD.FN的陳述, 而對(duì)主體和客體沒(méi)有要求. 作為一個(gè)特殊的縮寫(xiě),
listStatements( S, P, O )
等同與
listStatements( new SimpleSelector( S, P, O ) )
下面的代碼可以在Tutorial7中找到, 列舉了數(shù)據(jù)庫(kù)中所有vcard中的全名.
// select all the resources with a VCARD.FN property
ResIterator iter = model.listSubjectsWithProperty(VCARD.FN);
if (iter.hasNext()) {
System.out.println("The database contains vcards for:");
while (iter.hasNext()) {
System.out.println(" " + iter.nextStatement()
.getProperty(VCARD.FN)
.getString());
}
} else {
System.out.println("No vcards were found in the database");
}
這個(gè)會(huì)產(chǎn)生類(lèi)似如下的輸出:
The database contains vcards for:
Sarah Jones
John Smith
Matt Jones
Becky Smith
你的下一個(gè)練習(xí)是修改此代碼以使用SimpleSelector而不是使用listSubjectsWithProperty來(lái)達(dá)到相同的效果.
讓我們看看如何對(duì)所選擇的陳述實(shí)行更好的控制. SimpleSelector可以被繼承, 它的select方法可以被修改來(lái)實(shí)現(xiàn)更好的過(guò)濾:
// select all the resources with a VCARD.FN property
// whose value ends with "Smith"
StmtIterator iter = model.listStatements(
new SimpleSelector(null, VCARD.FN, (RDFNode) null) {
public boolean selects(Statement s)
{return s.getString().endsWith("Smith");}
});
完整的代碼可以在Tutorial8中找到, 并會(huì)產(chǎn)生如下的輸出:
The database contains vcards for:
John Smith
Becky Smith
你也許會(huì)認(rèn)為下面的代碼:
// do all filtering in the selects method
StmtIterator iter = model.listStatements(
new
SimpleSelector(null, null, (RDFNode) null) {
public boolean selects(Statement s) {
return (subject == null || s.getSubject().equals(subject))
&& (predicate == null || s.getPredicate().equals(predicate))
&& (object == null || s.getObject().equals(object))
}
}
});
等同于:
StmtIterator iter =
model.listStatements(new SimpleSelector(subject, predicate, object)
________________________________________
對(duì)模型的操作
Jena提供了把模型當(dāng)作一個(gè)集合整體來(lái)操縱的三種操作方法. 即三種常用的集合操作:并, 交和差.
兩個(gè)模型的并操作就是把表示兩個(gè)模型的陳述集的并操作. 這是RDF設(shè)計(jì)所支持的關(guān)鍵操作之一. 它此操作允許把分離的數(shù)據(jù)源合并到一起. 考慮下面兩個(gè)模型:
當(dāng)它們被合并時(shí), 兩個(gè)http://...JohnSmith會(huì)合并成一個(gè), 重復(fù)的vcard:FN箭頭會(huì)被丟棄, 此時(shí)就會(huì)產(chǎn)生:
// read the RDF/XML files
model1.read(new InputStreamReader(in1), "");
model2.read(new InputStreamReader(in2), "");
Model model = model1.union(model2);
model.write(system.out, "RDF/XML-ABBREV");
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:vcard="http://www.w3.org/2001/vcard-rdf/3.0#">
<rdf:Description rdf:about="http://somewhere/JohnSmith/">
<vcard:EMAIL>
<vcard:internet>
<rdf:value>John@somewhere.com</rdf:value>
</vcard:internet>
</vcard:EMAIL>
<vcard:N rdf:parseType="Resource">
<vcard:Given>John</vcard:Given>
<vcard:Family>Smith</vcard:Family>
</vcard:N>
<vcard:FN>John Smith</vcard:FN>
</rdf:Description>
</rdf:RDF>
聯(lián)系客服