XQuery/XML 到 RDF
外觀
< XQuery
對於 Emp-DEPT 案例研究,必須從底層 XML 檔案生成 RDF。XQuery 指令碼生成 RDF。它使用配置檔案來定義如何將表的列對映到 RDF 以及要使用的名稱空間。這種對映需要更多工作才能允許複合鍵並允許使用者定義的轉換。用於建立此對映的互動式工具將很有用。
在網路上釋出連結資料的首要指南是 如何在網路上釋出連結資料。這項與華夏公益教科書條目相關的工作在於逐步應用其中闡述的原則。
這種轉換說明了本地資料集(無論是 SQL 還是 XML)與旨在融入全球資料庫的資料集之間的一些差異。一些決定仍然不清楚。
- 表隱式地處於組織上下文之中。此上下文必須透過為本地屬性和識別符號建立名稱空間來新增到 RDF 中
- 查詢的範圍隱式地處於組織邊界內,但在 RDF 中,此範圍需要明確。在 SQL 查詢中 select * from emp; emp 模糊地既是員工類,也是公司中的員工集。在 RDF 中,這需要明確,因此需要新增兩種型別的元組
- 元組將員工型別與公司的員工定義聯絡起來
- 元組將員工與公司聯絡起來(待新增)
- 與全球資料庫的連結需要兩種型別的連結
- 本地屬性需要對映到全域性謂詞。這裡,員工姓名對映到 foaf:surname(但案例可能需要更改)。或者,可以定義本地謂詞 f:name,它與 foaf 謂詞使用 owl:samePropertyAs 等效。
- 資源的本地識別符號需要替換為全域性 URI。這裡,位置對映到 dbpedia 資源 URI。或者,本地 URI f:location/Dallas 可以與 dbPedia 資源使用 owl:sameAs 等效。(在哪裡?為什麼延遲這一點?)
- 外部索引鍵被替換為完整的 URI,直接指向連結的資源。此屬性的名稱不再是外部索引鍵的名稱(例如 MgrNo,而是相關資源的名稱(Manager)。但是,外部索引鍵本身也可能需要替換。
- 主鍵也被替換為 URI,但本地主鍵值(例如員工編號)將需要作為文字保留,如果它不是純粹的代理鍵。這可能應該對映到 rdf:label。
- 資料型別在資料中最好是顯式的,以避免在查詢中進行轉換,儘管這會增加 RDF 圖的大小。
- 名稱空間已在 RDF 屬性值中出現時完全展開。另一種方法是在 DTD 前言中定義實體作為這些名稱空間的簡寫,但並非所有 RDF 處理器都會進行展開。xml:base 可用於預設一個名稱空間。
[這裡做出的選擇是初學者的選擇,歡迎評論。]
一些尚未解決的問題
- 關於整個資料集的元資料 - 它的來源、轉換時間和方式 - 這些可以是文件的 DC 屬性,每個實體都作為文件的一部分與其繫結?
- 另一種對映方法是從本體開始,向其新增對映資訊,而不是從臨時配置檔案中生成對映資訊。
為了便於從 XML 轉換為 RDF,定義了一個單獨的配置檔案。這是 emp-dept 資料的配置檔案。
<?xml version="1.0" encoding="UTF-8"?>
<XML-to-RDF>
<namespaces>
<namespace prefix="f" uri="http://www.cems.uwe.ac.uk/empdept/concept/" />
<namespace prefix="ft" uri="http://www.cems.uwe.ac.uk/empdept/"/>
<namespace prefix="rdf" uri="http://www.w3.org/1999/02/22-rdf-syntax-ns#" />
<namespace prefix="rdfs" uri="http://www.w3.org/2000/01/rdf-schema#" />
<namespace prefix="foaf" uri="http://xmlns.com/foaf/0.1/" />
<namespace prefix="xs" uri="http://www.w3.org/2001/XMLSchema#" />
</namespaces>
<map type="emp" prefix="f">
<syntaxhighlight file="/db/Wiki/empdept/emp.xml" path="//Emp"/>
<col name="EmpNo" pk="true" uribase="ft:emp" type="xs:string"/>
<col name="Ename" prefix="rdfs" tag="label"/>
<col name="Sal" type="xs:integer"/>
<col name="Comm" type="xs:integer"/>
<col name="HireDate" type="xs:date"/>
<col name="MgrNo" tag="Mgr" uribase="ft:emp"/>
<col name="MgrNo"/>
<col name="DeptNo" tag="Dept" uribase="ft:dept"/>
<col name="Ename" prefix="foaf" tag="surname"/>
<col name="Job"/>
</map>
<map type="dept" prefix="f">
<syntaxhighlight file="/db/Wiki/empdept/dept.xml" path="//Dept"/>
<col name="Dname" prefix="rdfs" tag="label"/>
<col name="Dname"/>
<col name="Location" uribase="http://dbpedia.org/resource"/>
<col name="DeptNo" pk="true" uribase="ft:dept" type="xs:string"/>
</map>
<map type="salgrade" prefix="f">
<syntaxhighlight file="/db/Wiki/empdept/salgrade.xml" path="//SalGrade"/>
<col name="HiSal" type="xs:integer"/>
<col name="LoSal" type="xs:integer"/>
<col name="Grade" pk="true" uribase="ft:grade" type="xs:integer"/>
<col name="Grade" prefix="rdfs" tag="label"/>
</map>
</XML-to-RDF>
一個函式 row-to-rdf 生成表的行的 RDF,另一個函式 map-to-schema 生成表中使用的謂詞的 RDFS 描述。
module namespace fr= "http://www.cems.uwe.ac.uk/wiki/fr";
import module namespace util = "http://exist-db.org/xquery/util";
declare namespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
declare namespace rdfs = "http://www.w3.org/2000/01/rdf-schema#";
declare function fr:declare-namespaces($config) {
for $ns in $config//namespace[@declare="yes"]
return util:declare-namespace($ns/@prefix,xs:anyURI($ns/@uri))
};
declare function fr:expand($qname as xs:string?, $map ) as xs:string ?{
let $namespace := $map/..//namespace
return
if ($qname)
then if (contains($qname,":"))
then let $qs := tokenize($qname,":")
let $prefix := $qs[1]
let $name := $qs[2]
let $uri := $namespace[@prefix=$prefix]/@uri
return concat($uri,$name)
else if ($namespace[@prefix = $qname])
then
$namespace[@prefix = $qname]/@uri
else
$qname
else ()
};
declare function fr:row-to-rdf($row as element() , $map as element() ) as element(rdf:Description) * {
let $pk := $map/col[@pk="true"]
let $pkv := string($row/*[name()=$pk/@name])
let $pkuri := fr:expand($pk/@uribase, $map)
return
<rdf:Description>
{attribute rdf:about {concat($pkuri,"/",$pkv)}}
{ if ($map/@type)
then
let $typeuri := fr:expand(concat($map/@prefix,":",$map/@type),$map)
return <rdf:type rdf:resource="{$typeuri}"/>
else ()
}
{for $col in $map/col
let $name := $col/@name
let $data := string($row/*[name(.)=$name])
return
if ($data !="")
then
element { concat(($col/@prefix,$map/@prefix)[1], ":", ($col/@tag,$name)[1])}
{
if ($col/@type)
then (attribute rdf:datatype
{ fr:expand($col/@type,$map)} ,
$data)
else if ( $col/@uribase )
then attribute rdf:resource
{concat(fr:expand($col/@uribase,$map), "/",replace($data," ","_"))}
else $data
}
else ()
}
</rdf:Description>
};
declare function fr:map-to-schema ($map as element()) as element(rdf:Description) * {
let $typeuri := fr:expand(concat($map/@prefix,":",$map/@type),$map)
for $col in $map/col[@type]
let $prop := concat( fr:expand(($col/@prefix,$map/@prefix)[1],$map ), ($col/@tag,$col/@name)[1])
let $rangeuri := ( fr:expand($col/@type,$map), fr:expand($col/@uribase,$map),"http://www.w3.org/2000/01/rdf-schema#literal")[1]
return
<rdf:Description rdf:about="{$prop}">
<rdf:type rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"/>
<rdfs:domain rdf:resource="{$typeuri}"/>
<rdfs:range rdf:resource="{$rangeuri}"/>
<rdf:label>{string($col/@name)}</rdf:label>
</rdf:Description>
};
用於生成完整資料庫的 RDF 的指令碼
import module namespace fr="http://www.cems.uwe.ac.uk/wiki/fr" at "fr.xqm";
declare namespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
declare namespace rdfs = "http://www.w3.org/2000/01/rdf-schema#";
declare variable $config := doc(request:get-parameter("config",()));
declare variable $x := fr:declare-namespaces($config);
<rdf:RDF>
{
for $map in $config//map
let $xml := doc($map/source/@file)
let $source := util:eval(concat("$xml",$map/source/@path))
return
(for $row in $source return fr:row-to-rdf($row,$map),
fr:map-to-schema($map)
)
}
</rdf:RDF>
此外,每個資源都作為 RDF 檢索。在此簡單示例中,對像這樣的資源 URI 的請求
http://www.cems.uwe.ac.uk/empdept/emp/7839
由 Apache 重寫為
http://www.cems.uwe.ac.uk/xmlwiki/RDF/empdeptrdf.xq?emp=7839
並且指令碼直接從 RDF 檔案中檢索所選資源的 RDF:Description。
這種機制不符合區分資訊資源(如關於員工 7839 的資訊)和所表示的現實世界實體的推薦做法。目前,資源 URI 直接取消引用到 RDF,而不是使用推薦的 303 機制進行間接取消引用。
declare namespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
declare variable $rdf := doc("/db/Wiki/RDF/empdept.rdf");
declare option exist:serialize "media-type=application/rdf+xml";
(: better to just parse the uri itself :)
let $param := request:get-parameter-names()
let $type := $param[1]
return
if ($type="all")
then
$rdf
else
let $key := request:get-parameter($type,())
let $resourceuri := concat("http://www.cems.uwe.ac.uk/empdept/",$type,"/",$key)
return
<rdf:RDF>
{$rdf//rdf:Description[@rdf:about=$resourceuri]}
</rdf:RDF>
- 複合主鍵
- 轉換函式,例如將字串的大小寫轉換、重新格式化日期
- 新增的資源和關係 - 這裡有公司實體以及從部門到公司的連結