跳至內容

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

華夏公益教科書