新版Jena文档《An Introduction to RDF and the Jena RDF API》的译文Word文档下载推荐.docx
《新版Jena文档《An Introduction to RDF and the Jena RDF API》的译文Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《新版Jena文档《An Introduction to RDF and the Jena RDF API》的译文Word文档下载推荐.docx(32页珍藏版)》请在冰点文库上搜索。
导言
资源描述框架是(RDF)是描述资源的一项标准(在技术上是W3C的推荐标准)。
什么是资源?
这实在是一个很难回答的问题,其精确的定义目前尚在争论中。
出于我们的目的,我们可以把资源想象成任何我们可以确定识别的东西。
在本教程中,读者你本身就是一个资源,而你的主页也是一个资源,数字1和故事中巨大的白鲸都是资源。
在本教程中,我们的例子会围绕人们展开。
假设人们会使用VCARDS,而VCARD将由RDF表示机制来描述。
我们最好把RDF考虑成由结点和箭头的形式构成的图。
一个简单的vcard在RDF中可能看起来是这样的:
资源JohnSmith在图中用椭圆表示,并被一个统一资源定位符(URI)所标识,在本例中是"
http:
//.../JohnSmith"
)。
如果你想要通过你的浏览器来访问这个资源的话,你很有可能会失败。
四月的愚人节笑话并不经得起考验,相反如果你的浏览器把JohnSmith传递到你的桌面的话,你才该感到惊讶。
如果你并不熟悉URI'
s的话,你可以把它们想象成简单的陌生名字。
资源拥有属性(property)。
在这些例子中,我们对JohnSmith名片上出现的那些属性很感兴趣。
图1只显示了一个属性,JohnSmith的全名。
属性是由标有属性名的箭头表示的。
属性的名字也是一个URI,但是由于URI十分冗长笨重,所以图中将它显示为XMLqname的形式。
在'
:
'
之前的部分称为命名空间前缀并表示了一个命名空间。
之后的部分称为局部名,并表示在命名空间中的一个名字。
在写成RDFXML形式时,属性常常以qname的形式表示,这是一个在图形和文本中的简单的缩写方法。
然而,严格地讲,属性应该用URI来标识。
命名空间前缀:
局部名的形式是一种命名空间连接局部名的URI缩写。
当浏览器访问时,用并没有强制属性的URI必须指向一些具体的事物。
每个属性都有一个值。
在此例中,值为一个文本(literal),我们现在可以把它看成一个字符串。
文本在图中显示为长方形。
Jena是一个JavaAPI,我们可以用它来创建和操纵诸如上述例图的RDF图。
Jena设有表示图(graph),资源(resource),属性和文本(literal)的对象类。
表示资源,属性和文本的接口分别称为Resource,Property,和Literal。
在Jena中,一个图(graph)被称为一个模型并被Model接口所表示。
创建上述例图或称为上述模型的代码很简单:
//somedefinitions
staticStringpersonURI="
//somewhere/JohnSmith"
;
staticStringfullName="
JohnSmith"
//createanemptyModel
Modelmodel=ModelFactory.createDefaultModel();
//createtheresource
ResourcejohnSmith=model.createResource(personURI);
//addtheproperty
johnSmith.addProperty(VCARD.FN,fullName);
这些代码先定义了一些常量,然后使用了ModelFactory类中的createDefaultMode()方法创建了一个空的基于内存存储的模型(Model或model)。
Jena还包含了Model接口的其他实现方式。
例如,使用关系数据库的,这些类型Model接口也可以从ModelFactory中创建。
于是JohnSmith这个资源就被创建了,并向其添加了一个属性。
此属性由一个"
常"
("
constant"
)类VCARD提供,这个类保存了在VCARD模式(schema)中所有定义的表示对象。
Jena也为其他一些著名的模式提供了常类的表示方法,例如是RDF和RDF模式,Dublin核心标准和DAML。
创建资源和添加属性的代码可以写成更紧凑的层叠形式:
ResourcejohnSmith=
model.createResource(personURI)
.addProperty(VCARD.FN,fullName);
这个例子的工作代码可以在Jena发布的材料的教程包中的Tutorial1中找到。
作为练习,你自己可以获得此代码并修改其以创建一个简单VCARD。
现在让我们为vcard再增加一些更详细的内容,以便探索更多的RDF和Jena的特性。
在第一个例子里,属性值为一个文本。
然而RDF属性也可以采用其他的资源作为其属性值。
下面这个例子使用常用的RDF技术展示了如何表示JohnSmith名字的不同部分:
在这里我们增加了一个新的属性,vcard:
N,来表示JohnSmith名字的结构。
这个模型有几点有趣之处。
注意属性vcard:
N使用一个资源作为起属性值。
同时注意代表复合名字的椭圆并没有URI标识。
它被认为是一个空白结点(blankNode)。
创建此例的Jena代码也十分简单。
首先是一些声明和对空模型的创建。
StringpersonURI="
StringgivenName="
John"
StringfamilyName="
Smith"
StringfullName=givenName+"
"
+familyName;
//andaddthepropertiescascadingstyle
ResourcejohnSmith
=model.createResource(personURI)
.addProperty(VCARD.FN,fullName)
.addProperty(VCARD.N,
model.createResource()
.addProperty(VCARD.Given,givenName)
.addProperty(VCARD.Family,familyName));
此例的工作代码可以在Jena发布材料的教程包的Tutorial2中得到。
陈述
RDF模型中的每一个箭头表示为一个陈述(statement)。
每一个陈述声明了关于某个资源的某个事实。
一个陈述有三部分组成。
主体,也就是箭头的出发的资源。
谓词,也就是标识箭头的属性。
客体,也就是箭头所指向的那个资源或文本。
一个陈述有时也叫做一个三元组的原因就是它由三部分组成。
一个RDF模型(译者注:
指Jena中的接口Model)是由一组陈述所组成的。
在Tutorial2中,每调用一次addProperty函数就会在模型中增加另一个陈述。
(因为一个模型是由一组陈述组成的,所以增加一个重复的陈述并不会产生任何意义。
)Jena模型接口定义了一个listStatements()方法,此方法会返回一个StmtIterator类型的变量。
StmtItor是Java中Iterator的一个子类型,这个StmtIterator变量重复迭代了该接口模型中的所有陈述。
StmtIterator类型中有一个方法nextStatement(),该方法会从iterator返回下一个陈述。
(就和next()返回的一样,但是已将其映射为Statement类型)。
接口Statement提供了访问陈述中主体,谓词和客体的方法。
现在我们会用使用那个接口来扩展Tutorial2,使起列出所有的创建的陈述并将它们打印出来。
此例完整的代码可以在Tutorial3中找到。
//listthestatementsintheModel
StmtIteratoriter=model.listStatements();
//printoutthepredicate,subjectandobjectofeachstatement
while(iter.hasNext()){
Statementstmt=iter.nextStatement();
//getnextstatement
Resourcesubject=stmt.getSubject();
//获得主体
Propertypredicate=stmt.getPredicate();
//获得谓语
//此处应注意!
和java中Object要区分
RDFNodeobject=stmt.getObject();
//获得客体!
System.out.print(subject.toString());
System.out.print("
+predicate.toString()+"
);
if(objectinstanceofResource){
System.out.print(object.toString());
}else{
//objectisaliteral
\"
"
+object.toString()+"
\"
}
System.out.println("
."
}
因为一个陈述的客体可以是一个资源也可以是一个文本。
getObject()方法会返回一个类型为RDFNode的客体,RDFNode是Resource和Literal类共同的超类。
为了确定本例中的客体确切的类型,代码中使用instanceof来确定其类型和相应的处理。
运行后,此程序回产生与此相似的输出:
//somewhere/JohnSmithhttp:
//www.w3.org/2001/vcard-rdf/3.0#Nanon:
14df86:
ecc3dee17b:
-7fff.
anon:
-7fffhttp:
//www.w3.org/2001/vcard-rdf/3.0#Family"
.
//www.w3.org/2001/vcard-rdf/3.0#Given"
//www.w3.org/2001/vcard-rdf/3.0#FN"
现在你明白了为什么模型构建会更加清晰。
如果你仔细观察,就会发现上面每一行都由三个域组成,这三个域分别代表了每一个陈述的主体,谓词和客体。
在此模型中有四个箭头,所以会有四个陈述。
-7fff"
是有Jena产生的一个内部标识符,它不是一个URI,也不应该与URI混淆。
它只是Jena处理时使用的一个内部标号。
W3C的RDF核心工作小组定义了一个类似的表示符号称为N-三元组(N-Triples)。
这个名字表示会使用"
三元组符号(triplenotation)"
。
在下一节中我们会看到Jena有一个内置的N-三元组写机制(N-Tripleswriter)。
写RDF
Jena设(she)有读写XML形式的RDF方法。
这些方法可以被用来将一个RDF模型保存到文件并在日后重新将其读回。
Tutorial3创建了一个模型并将其以三元组的形式输出。
Tutorial4对Tutorial3做了修改,使其将此模型以RDFXML的形式输出到标准输出流中。
这个代码依然十分简单:
model.write可以带一个OutputStream的参数。
//nowwritethemodelinXMLformtoafile
model.write(System.out);
应该有类似的输出:
<
rdf:
RDF
xmlns:
rdf='
//www.w3.org/1999/02/22-rdf-syntax-ns#'
vcard='
//www.w3.org/2001/vcard-rdf/3.0#'
>
<
Descriptionrdf:
about='
//somewhere/JohnSmith'
>
vcard:
FN>
JohnSmith<
/vcard:
Nrdf:
nodeID="
A0"
/>
/rdf:
Description>
Given>
John<
Family>
Smith<
RDF>
W3C的RDF规格说明书规定了如何用XML的形式来表示RDF。
RDFXML的语法十分复杂。
读者可以在RDF核心工作小组制定的RDF入门篇(primer)中找到更详细的指导。
但是不管怎么样,让我们先迅速看一下应该如何解释上面的RDFXML输出
RDF常常嵌入在一个<
元素中。
如果有其他的方法知道此XML是RDF的话,该元素是可以不写的。
然而我们常常会使用它。
在这个RDF元素中定义了两个在本文档中使用的命名空间。
接下来是一个<
元素,此元素描述了URI为"
的资源。
如果其中的rdf:
about属性被省略的话,这个元素就表示一个空白结点。
元素描述了此资源的一个属性。
属性的名字"
FN"
是属于vcard命名空间的。
RDF会通过连接命名空间前缀的URI和名字局部名"
来形成该资源的URI"
//www.w3.org/2001/vcard-rdf/3.0#FN"
这个属性的值为文本"
JohnSmith"
N>
元素是一个资源。
在此例中,这个资源是用一个相对URI来表示的。
RDF会通过连接这个相对URI和此文档的基准URI来把它转换为一个绝对URI。
但是,在这个RDFXML输出中有一个错误,它并没有准确地表示我们所创建的模型。
模型中的空白结点被分配了一个URI。
它不再是空白的了。
RDF/XML语法并不能表示所有的RDF模型。
例如它不能表示一个同时是两个陈述的客体的空白结点。
我们用来写这个RDF/XML的'
哑'
writer方法并没有试图去正确的书写这个模型的子集,虽然其原本可以被正确书写。
它给每一个空白结点一个URI,使其不再空白。
Jena有一个扩展的接口,它允许新的为不同的RDF串行化语言设计的writer可以被轻易地插入。
以上的调用会激发一个标准的'
writer方法。
Jena也包含了一个更加复杂的RDF/XMLwriter,它可以被用携带另一个参数的write()方法所调用。
model.write(System.out,"
RDF/XML-ABBREV"
此writer,也就是所谓的PrettyWriter,利用RDF/XML缩写语法把模型写地更为紧凑。
它也能保存尽可能保留空白结点。
然而,它并不合适来输出大的模型。
因为它的性能不可能被人们所接受。
要输出大的文件和保留空白结点,可以用N-三元组的形式输出:
N-TRIPLE"
这会产生类似于Tutorial3的输出,此输出会遵循N-三元组的规格。
读RDF
Tutorial5演示了如何将用RDFXML记录的陈述读入一个模型。
在此例中,我们提供了一个小型RDF/XML形式的vcard的数据库。
下面代码会将其读入和写出。
注意:
如果要运行这个小程序,应该把输入文件放在你的classpath所指向的目录或jar中。
//createanemptymodel
//usetheFileManagertofindtheinputfile
InputStreamin=FileManager.get().open(inputFileName);
if(in==null){
thrownewIllegalArgumentException(
File:
+inputFileName+"
notfound"
}
//readtheRDF/XMLfile
model.read(in,null);
//writeittostandardout
read()方法中的第二个参数是一个URI,它是被用来解决相对URI的。
因为在测试文件中没有使用相对URI,所以它允许被置为空值。
运行时,Tutorial5会产生类似如下的XML输出:
//somewhere/JohnSmith/'
//somewhere/SarahJones/'
SarahJones<
A1"
//somewhere/MattJones/'
MattJones<
A2"
A3"
Rebecca<
Jones<
Sarah<
Matthew<
//somewhere/RebeccaSmith/'
BeckySmith<
控制前缀
explicitprefixdefinitions
Intheprevioussection,wesawthattheoutputXMLdeclaredanamespaceprefixvcardandusedthatprefixtoabbreviateURIs.WhileRDFusesonlythefullURIs,andnotthisshortenedform,Jenaprovideswaysofcontrollingthenamespacesusedonoutputwithitsprefixmappings.Here'
sasimplee