XQuery/SPARQL 獲取國家區號
受 Henry Story 的部落格文章 啟發,以下指令碼解決了相同的問題。此指令碼使用先前模組中定義的函式在 dbpedia 伺服器上執行 SPARQL 查詢,並將 SPARQL 查詢結果轉換為元組。
import module namespace fr="http://www.cems.uwe.ac.uk/wiki/fr" at "fr.xqm";
declare variable $query := "
PREFIX : <http://dbpedia.org/resource/>
PREFIX p: <http://dbpedia.org/property/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT * WHERE {
?resource p:callingCode ?callingCode.
}
";
declare option exist:serialize "method=xhtml media-type=text/html";
<html>
<head>
<title>Country Calling codes</title>
</head>
<body>
<h1>Country Calling codes</h1>
<table border="1">
{ for $country in fr:sparql-to-tuples(fr:execute-sparql($query))
let $name := fr:clean($country/resource)
order by $name
return
<tr>
<td><a href="{$country/resource}">{$name}</a></td>
<td>{$country/callingCode}</td>
</tr>
}
</table>
</body>
</html>
在此指令碼中,資源 URI 被解析以在 fr:clean() 函式中獲取資源 URI 的本地名稱部分。
更合理的替代方案是過濾多語言 rdfs:label 屬性
SELECT * WHERE {
?resource p:callingCode ?callingCode.
?resource rdfs:label ?name.
FILTER (lang(?name) = 'en')
}
但此查詢自然慢得多。
此查詢返回一組具有 callingCode 屬性的 dbpedia 資源。但是,它包含不是國家的資源,並且證明很難確定哪些資源是國家。人們可能會期望 skos:subject 或 rdfs:type 謂詞會識別國家,但事實並非如此。
當然,哪些實體被歸類為國家是一個有爭議的問題,正如科索沃和 ISO 3166 文件目前所說明的那樣。也許可以透過屬性更好地識別國家。有一個看起來很有希望的屬性 countryCode
SPARQL 查詢變為
PREFIX : <http://dbpedia.org/resource/> PREFIX p: <http://dbpedia.org/property/> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT * WHERE { ?resource p:callingCode ?callingCode. ?resource p:countryCode ?countryCode. }
但是這表明許多國家在 dbpedia 中的資料不完整,或者此屬性的編碼不一致。這並不奇怪,因為存在多種型別的國家程式碼,從而導致對國家的不同定義
事實上,國際區號列在 維基百科條目 中。因此,一種更直接的方法是透過直接抓取維基百科來生成表格。但是,現在我們犯了相反的錯誤,因為除了國家之外,電信服務也有區號,並且數字和名稱的格式不一致 - 一些有多個數字,一些數字前面有 +,一些國家後面附加了同義詞等。
在此指令碼中,路徑表示式查詢錨點“Alphabetical_Listing”,然後查詢以下表格。
declare namespace h= "http://www.w3.org/1999/xhtml" ;
let $url := "http://en.wikipedia.org/wiki/International_calling_codes"
let $wikipage := doc($url)
let $section := $wikipage//h:table[@class="wikitable sortable"][2]
return
$section
2010 年 1 月 - 頁面佈局已更改,因此此表之前的路徑
let $section := $wikipage//h:a[@name="Alphabetical_Listing"]/../following-sibling::h:table[1]
到當前
let $section := $wikipage//h:table[@class="wikitable sortable"][2]
另一種方法是將此表匯出為 RDF。這裡資源是 dbpedia 資源,屬性在 dbpedia 屬性名稱空間中定義。
declare namespace h= "http://www.w3.org/1999/xhtml" ;
declare namespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
declare namespace p = "http://dbpedia.org/property/";
let $url := "http://en.wikipedia.org/wiki/International_calling_codes"
let $wikipage := doc($url)
let $section := $wikipage//h:table[@class="wikitable sortable"][2]
return
<rdf:RDF xmlns:p = "http://dbpedia.org/property/">
{for $row in $section/h:tr[h:td]
let $country := string($row/h:td[1])
let $code := string($row/h:td[2]/h:a[1])
let $code := replace($code,"\*","")
let $resource := concat("http://dbpedia.org/resource/", replace($country," ","_"))
return
<rdf:Description rdf:about="{$resource}">
<p:internationalcallingCode>{$code}</p:internationalcallingCode>
</rdf:Description>
}
</rdf:RDF>
同樣,此表的結構也發生了變化,因此需要更新此程式碼。