跳轉到內容

XQuery/連結收集

來自華夏公益教科書

您想收集部落格頁面上的連結。

我們使用 doc() 函式對遠端網頁執行 HTTP GET 操作。如果頁面是格式良好的 XML 檔案,那麼您可以透過向 doc 函式新增 ul 謂詞來提取所有無序列表項。


此指令碼獲取部落格頁面並選擇連結部分中的 URL,這些 URL 引用其他部落格文章。獲取每個引用的文章並選擇標記為外部的 URL。結果以 XML 格式返回。

declare namespace q = "http://www.w3.org/1999/xhtml";

<results>
{
let $nav := doc("http://www.advocatehope.org/tech-tidbits/theory-of-the-web-as-one-big-database")//q:ul[@class="portletNavigationTree navTreeLevel0"]
for $href in $nav//@href
let $page := data($href)
let $content := doc($page)//q:div[@id="content"]
for $links in $content//q:a[@title="external-link"]
return
   <link>{ data($links/@href) }</link>
}
</results>

執行

刪除中間變數可以更清晰地看到結構

declare namespace q = "http://www.w3.org/1999/xhtml";

let $uri := "http://www.advocatehope.org/tech-tidbits/theory-of-the-web-as-one-big-database"
return
<results>
{
       for $page in doc($uri)//q:ul[@class="portletNavigationTree navTreeLevel0"]//@href
       for $link  in doc($page)//q:div[@id="content"]//q:a[@title="external-link"]/@href
       return 
          <link>{data($link)}</link>
}
</results>

執行

資源庫模式

[編輯 | 編輯原始碼]

Daniel 正在提議一項支援從站點中提取此類資料的標準。此類模式將定義一組文件的檢視,該檢視足以允許以上提取基於模式。

我們可以透過用添加了實現相關的路徑的 ER 模型表示的檢視模式來實現這一目標。


<model  name="blog-links">
    <type name="url" datatype="string"/>
    <entity name="page"  >
        <attribute name="inner"  max="N"   path="//q:ul[@class='portletNavigationTree navTreeLevel0']//@href"  type="page"/>
        <attribute name="external" max="N"  path="//q:div[@id='content']//q:a[@title='external-link']/@href"  type="url"/>
     </entity>
</model>

然後,此模式可以被通用指令碼連結收集指令碼使用

let $start := request:get-parameter("page",())
let $view := request:get-parameter("view",())
let $schema := doc($view)
let $inner := $schema//entity[@name='page']/attribute[@name='inner']/@path 
let $external := $schema//entity[@name='page']/attribute[@name='external']/@path  
return
<results>
{
       for $page in util:eval(concat('doc($start)',$inner))
       for $link in util:eval(concat('doc($page)',$external))
       return      
         <link>{string($link)}</link>
}
</results>

此指令碼現在在任何頁面結構可以在模式方面用適當的路徑定義的站點上執行連結收集任務。

執行

相對和絕對 URI

[編輯 | 編輯原始碼]

前一個版本僅在 URI 為絕對值時才有效。如果 URI 不是絕對值,則需要做更多工作。

declare namespace q = "http://www.w3.org/1999/xhtml";

declare variable $start := request:get-parameter("page",());
declare variable $view := request:get-parameter("view",());
declare variable $schema := doc($view);
declare variable $base :=  substring-before($start,local:local-uri($start));

declare function local:local-uri($uri) {
  if (contains($uri,"/"))
  then local:local-uri(substring-after($uri,"/"))
  else $uri
};

declare function local:absolute-uri($url) {
   if (starts-with($url,"http://"))
   then $url
   else concat($base,$url)
};

let $inner := $schema//entity[@name='page']/attribute[@name='inner']/@path 
let $external := $schema//entity[@name='page']/attribute[@name='external']/@path  

let $starturi := local:absolute-uri($start)
return
<results>

{
       for $page in util:eval(concat('doc($starturi)',$inner))
       let $pageuri := local:absolute-uri($page)
       for $link in util:eval(concat('doc($pageuri)',$external))
       return      
         <link>{string($link)}</link>
}
</results>

因此,使用不同的模式 - 相同的模型,不同的路徑

<model name="site-links">
    <type name="url" datatype="string"/>
    <entity name="page"  >
         <attribute name="inner" max="N" path="//div[@class='nav']//a/@href" type="page"/>
        <attribute name="external" max="N" path="//div[@class='content']//a/@href" type="url"/>
    </entity>
</model>

這是 測試站點 的檢視模式

執行


虛擬路徑

[編輯 | 編輯原始碼]

導航路徑仍然在指令碼中硬編碼。我們希望編寫路徑表示式,其中步驟在模式中定義。然後,此路徑將在模式的上下文中解釋。

檢視模式

[編輯 | 編輯原始碼]

在此示例中,測試站點已擴充套件為包括一個單獨的索引頁面以及檢視中的一些其他元件

<model name="site-links">
    <entity name="externalPage">
        <attribute name="title" path="/head/title"/>
    </entity>
    <entity name="index">
        <attribute name="link" max="N" path="//div[@class='index']//a/@href" type="page"/>
     </entity>
     <entity name="page">
        <attribute name="title" path="//head/title"/>
        <attribute name="inner" max="N" path="//div[@class='nav']//a/@href" type="page"/>
        <attribute name="external" max="N" path="//div[@class='content']//a/@href"
        type="externalPage"/>
         <attribute name="author" min="0" path="//div[@class='content']/span[@class='author']"/>
    </entity>
</model>

索引

路徑語言

[編輯 | 編輯原始碼]

此原型使用簡單的路徑語言。步驟 -> 取消引用相對或絕對 URL。如果步驟被識別為當前實體的屬性,則使用關聯的路徑表示式,否則步驟將作為 XPath 執行。第一步標識初始文件的(實體)型別。

例如

index/link/->/title

[編輯 | 編輯原始碼]

列出索引中頁面的標題。

import module namespace vp ="http://www.cems.uwe.ac.uk/xmlwiki/vp" at "../Gov/vp.xqm";

let $uri := "http://www.cems.uwe.ac.uk/xmlwiki/Gov/site/index.html"
let $schema := "/db/Wiki/Gov/site3.xml"
return
  <result>
  {vp:process-path($uri,"index/link/->/title",$schema) }
  </result>

執行

index/link/->/author/string(.)

[編輯 | 編輯原始碼]

列出索引中引用的頁面的作者。

import module namespace vp ="http://www.cems.uwe.ac.uk/xmlwiki/vp" at "../Gov/vp.xqm";

let $uri := "http://www.cems.uwe.ac.uk/xmlwiki/Gov/site/index.html"
let $schema := "/db/Wiki/Gov/site3.xml"
return
  <result>
  {vp:process-path($uri,"index/link/->/author/string(.)",$schema) }
  </result>

執行

page/inner/->/external

[編輯 | 編輯原始碼]

列出索引頁面引用的所有頁面的所有不同外部連結的 URL。

import module namespace vp ="http://www.cems.uwe.ac.uk/xmlwiki/vp" at "../Gov/vp.xqm";
declare option exist:serialize "method=xhtml media-type=text/html";

let $uri := "http://www.cems.uwe.ac.uk/xmlwiki/Gov/site/index.html"
let $schema := "/db/Wiki/Gov/site3.xml"
return
  <ul>
    {for $uri in distinct-values(vp:process-path($uri,"index/link/->/external",$schema))
    order by $uri
    return
    <li>
    <a href="{$uri}">{string($uri)}</a>
    </li>
   }
  </ul>

執行

page/inner/->/inner/->/title

[編輯 | 編輯原始碼]

列出連結到初始頁面的頁面的標題。

import module namespace vp ="http://www.cems.uwe.ac.uk/xmlwiki/vp" at "../Gov/vp.xqm";

let $uri := "http://www.cems.uwe.ac.uk/xmlwiki/Gov/site/test1.html"
let $schema := "/db/Wiki/Gov/site3.xml"
return
  <result>
  {vp:process-path($uri,"page/inner/->/inner/->/title",$schema) }
  </result>

執行

指令碼

[編輯 | 編輯原始碼]

核心函式在模式的上下文中處理虛擬路徑。


declare function vp:process-steps($nodes,$context,$steps,$base,$schema) {
if (empty($steps))
then $nodes
else 
 let $step := $steps[1]
 let $entity := $schema//entity[@name=$context]
 return 
    if ( $step = "->" )
    then 
          let $newnodes :=
               for $node in $nodes 
               return vp:get-doc($node,$base)
           return
             vp:process-steps($newnodes, $context, subsequence($steps,2),$base,$schema)
   else
   if ($entity/attribute[@name=$step])
      then 
      let $attribute :=$entity/attribute[@name=$step]
      let $next := string($schema//entity[@name=$attribute/@type]/@name)
      let $path := string($attribute/@path)
      let $newnodes := 
             for $node in $nodes
             let $newnode := util:eval(concat("$node",$path))
             return $newnode
      return
          vp:process-steps($newnodes, $next, subsequence($steps,2),$base,$schema)
  else 
       let $newnodes := 
             for $node in $nodes
             let $newnode := util:eval(concat("$node/",$step))
             return $newnode
      return
          vp:process-steps($newnodes, $context, subsequence($steps,2),$base,$schema) 
};

此示例基於 Daniel Bennett 的文章 [1]

華夏公益教科書