跳至内容

XQuery/SPARQL 获取国家区号

来自 Wikibooks,开放世界中的开放书籍

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

[编辑 | 编辑源代码]

另一种方法是将此表导出为 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>

同样,此表的结构也发生了变化,因此需要更新此代码。


RDF

华夏公益教科书