XQuery/連結收集
外觀
< 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 不是絕對值,則需要做更多工作。
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 執行。第一步標識初始文件的(實體)型別。
例如
列出索引中頁面的標題。
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>
列出索引中引用的頁面的作者。
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>
列出索引頁面引用的所有頁面的所有不同外部連結的 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>
列出連結到初始頁面的頁面的標題。
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]。