跳至內容

內容管理系統的 XQuery/站點地圖

來自華夏公益教科書,開放的書籍,開放的世界

您想使用 eXist 管理您的網站,並將每個集合用作 Web 內容資料夾。您需要一種方法來自動建立網站地圖,以便在 Web 根資料夾中新增新集合時,網站導航選單會自動更新。

我們將使用 eXist 的 get-child-collections() 函式來獲取根集合的所有子集合。我們建立一個遞迴函式來遍歷集合樹。

來自 eXist 函式庫,以下是 get-child-collections 函式的描述。

xmldb:get-child-collections($a as xs:string) xs:string*

Returns a sequence of strings containing all the child collections of the collection specified in $a.
The collection parameter can either be a simple collection path or an XMLDB URI.

如果我們有一個名為 /db/webroot 的集合,我們可以將此字串作為引數傳遞給此函式,所有子集合將作為字串序列返回。

然後我們可以建立一個遞迴函式,該函式作用於這些子集合中的每一個。

get-child-collections() 的示例用法

[編輯 | 編輯原始碼]

以下是用 get-child-collections() 函式的簡單示例。您只需傳遞一個引數,該引數是集合的路徑。它將返回該集合中所有子集合的序列。

xquery version "1.0";

let $children := xmldb:get-child-collections('/db/webroot')

return
<results>
   <children>{$children}</children>
</results>

站點地圖函式:版本 1

[編輯 | 編輯原始碼]
declare function local:sitemap($collection as xs:string) as node()* {
   if (empty(xmldb:get-child-collections($collection)))
      then ()
      else
         <ol>{
            for $child in xmldb:get-child-collections($collection)
            return
               <li>
                  <a href="{concat('/exist/rest', $collection, '/', $child)}">{$child}</a>
                  {local:sitemap(concat($collection, '/', $child))}
               </li>
        }</ol>
};

這個遞迴函式接受一個字串作為輸入引數,並返回一個複雜的節點。結果是 HTML 有序列表結構。它首先進行測試以檢視集合中是否存在任何子元素。如果不存在,它只返回。如果有新的子元素,則它建立一個新的有序列表,並遍歷該集合中的所有子元素,為每個子元素建立一個新的列表項,然後呼叫自身。請注意,這本可以寫成,使條件運算子僅在集合中存在子元素時才呼叫自身。

這是一個關於 尾遞迴 的示例。這種模式在 XQuery 函式中經常出現。

示例站點地圖程式

[編輯 | 編輯原始碼]

我們現在可以在 XHTML 頁面模板中呼叫此程式來建立一個網頁

原始碼

[編輯 | 編輯原始碼]
xquery version "1.0";
declare option exist:serialize "method=xhtml media-type=text/html indent=yes";

declare function local:sitemap($collection as xs:string) as node()* {
   if (empty(xmldb:get-child-collections($collection)))
      then ()
      else
         <ol>{
            for $child in xmldb:get-child-collections($collection)
            return
               <li>
                  <a href="{concat('/exist/rest', $collection, '/', $child)}">{$child}</a>
                  {local:sitemap(concat($collection, '/', $child))}
               </li>
        }</ol>
};

<html>
   <head>
      <title>Sitemap</title>
   </head>
   <body>
      <h1>Sitemap for collection /db/webroot</h1>
      {local:sitemap('/db/webroot')}
   </body>
</html>

新增標題

[編輯 | 編輯原始碼]

有時導航欄的標題將不同於集合的名稱。按照慣例,集合名稱通常只是沒有空格或大寫字母的簡短小寫字母。導航欄通常具有包含空格和大寫字母的標籤。

以下示例使用查詢表從 XML 檔案中查詢標題。

xquery version "1.0";
declare function local:sitemap($collection as xs:string) as node()* {
if (empty(xmldb:get-child-collections($collection)))
  then ()
  else
   <ol>{
      for $child in xmldb:get-child-collections($collection)
      let $db-path := concat($collection, '/', $child)
      let $path := concat('/exist/rest', $collection, '/', $child)
      let $lookup :=
doc('/db/apps/sitemap/06-collection-titles.xml')/code-table/item[$db-path=path]/title/text()
      order by $child
      return
         <li>
            <a href="{if (empty($lookup))
                      then ($path)
                      else (concat($path, "/index.xhtml"))}">
                      {if (empty($lookup)) then ($child) else ($lookup)}
            </a>
           {local:sitemap(concat($collection, '/', $child))}
         </li>
   }</ol>
};

螢幕影像

[編輯 | 編輯原始碼]

請注意,子集合都是按字母順序排序的。在某些情況下,這可能不是您希望顯示網站導航選單的順序。您可以向顯示標題的 XML 檔案新增一個 sort-order 引數元素,並使用該欄位對子集合進行排序。

集合標題檔案

[編輯 | 編輯原始碼]

將此檔案放在以下位置:/db/apps/sitemap/06-collection-titles.xml

<code-table>
    <item>
        <path>/db/webroot/about</path>
        <title>About</title>
    </item>
    <item>
        <path>/db/webroot/training</path>
        <title>Training</title>
    </item>
    <item>
        <path>/db/webroot/faqs</path>
        <title>Frequently Asked Questions</title>
    </item>
    <item>
        <path>/db/webroot/training/xforms</path>
        <title>XForms</title>
    </item>
    <item>
        <path>/db/webroot/training/rest</path>
        <title>ReST</title>
    </item>
    <item>
        <path>/db/webroot/training/xquery</path>
        <title>XQuery</title>
    </item>
    <item>
        <path>/db/webroot/training/tei</path>
        <title>Text Encoding Initiative</title>
    </item>
    <item>
        <path>/db/webroot/training/exist</path>
        <title>eXist</title>
    </item>
    <item>
        <path>/db/webroot/products</path>
        <title>Products</title>
    </item>
    <item>
        <path>/db/webroot/support</path>
        <title>Support</title>
    </item>
</code-table>

自定義站點地圖函式

[編輯 | 編輯原始碼]

並非所有集合都應該顯示在站點地圖中。某些集合可能包含您不想在公共站點地圖中顯示的私有管理資料。有兩種方法可以處理這個問題。您可以將一個通用的“已釋出集合”列表儲存在單獨的 XML 檔案中。或者,您可以在每個集合中儲存一個小的 XML 檔案來顯示該集合的屬性。預設情況下,此集合可以是公共的或私有的,具體取決於您編寫函式的方式。

如果您的同事和您各自都在構建希望共享的 Web 應用程式,則第二種選擇更具可移植性。透過在您的 collection-properties.xml 檔案上進行標準化,您可以將屬性儲存在集合中,然後透過交換可以壓縮的資料夾來交換它們與其他 eXist 站點。

計算集合和子集合中的檔案

[編輯 | 編輯原始碼]

以下是虛擬碼

declare function local:count-files-in-collection($collection as xs:string) as xs:integer {
let $child-collections := xmldb:get-child-collections($collection)
   if (empty($child-collections))
      then
         (: return the count of number of files in this collection :)
      else 
         (: for each subcollection call local:count-files-in-collection($child) :)
};
華夏公益教科書