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>
同样,此表的结构也发生了变化,因此需要更新此代码。