歡迎您光臨本站 註冊首頁

用 XQuery 製作指示板

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  
20 世紀 80 年代末出現的很多數字指示板更像是汽車的儀錶盤,很不精緻,或者說相當粗糙。其中更是少有能夠以一種吸引人的方式展示業務數據的。如今,基於 Web 的指示板能夠達到這樣的目的。通過本文,了解一個好的指示板是什麼樣的以及如何識別並利用關鍵績效指標(KPI)來製作更為有效的數字指示板。最後,使用 eXist XML 資料庫和 XQuery 構建一個 Web 指示板。

幾年前,我為一個客戶製作了大量與體育比賽有關的數據提要。我們需要尋求一種方法來體現此客戶的數據服務產品的廣度和深度,我們於是決定設計一個類似記分板似的東西放在客戶網站上。我們當時的想法是通過顯示關鍵的體育比賽數據,比如 “足球比賽得分”、“賽馬” 或 “板球比賽的次數” — 所有實時記錄的數據 — 來達到理想的效果並將此客戶數據服務的質量有效地傳達給潛在的顧客。

至於這個特定的記分板如何開發並非本文的目標:我之所以重新把它拿出來是因為在這個小部件部署后發生了一件特殊的事情。

常見的縮略詞
  • API: 應用程序編程介面(application programming interface)
  • CSS:層疊樣式表(Cascading Stylesheet)
  • HTML:超文本標記語言(Hypertext Markup Language)
  • HTTP:超文本傳輸協議(Hypertext Transfer Protocol)
  • UI:用戶界面(User Interface)
  • URL:統一資源定位符(Uniform Resource Locator)
  • XML:可擴展標記語言(Extensible Markup Language)
  • XSLT:可擴展樣式表語言轉換(Extensible Stylesheet Language Transform)

這個記分板投入使用后,我的這個客戶的高級管理層開始就所生成的數據提出問題。最初,這些問題圍繞著數據合計的準確性,隨後的問題愈發發人深省,比如 “我們應該顯示更多的足球得分” 或 “為何賽事多的時候更新速度要比平常的時候慢”。我們所生成的各種數字最終成為了衡量此客戶與體育比賽相關的數據提要的質量和總體狀況的有效基準數據。

由於這個計分板應用程序差不多每秒要更新一次,這樣就將此公司的運轉情況及時地傳遞給了高級管理層以供其快速地發現任何不正常之處。當然,我們所做的沒什麼新鮮的 — 只不過是開發 KPI 指示板理念的再現 — 但是創建它時加入了一些市場意識。

指示板概覽

在企業開發界,一段時期內,指示板曾經是人們大肆宣揚的一個主題,所以讓我先來給出指示板的一個非正式的定義,不過只限在本文中使用:

指示板 指的是實現一個或多個目標所需的重要信息的可視展示,這些信息經過整理並被恰當地擺放在屏幕上以便於人們一眼就能理解這些信息。

數據的目標和類型可以分為如下三個類別:

  • 戰略:戰略目標常常是公司的主管和決策者感興趣的,他們總是試圖更好地了解公司生產第一線的情況以便對公司的整體狀況有一個直觀的把握。
  • 分析:指的是推斷和辨別帶有分析性質的趨勢的目標。
  • 操作:在直接監視過程狀態的時候會出現操作數據;這類數據的例子很多,比如 “Web 站點是否正在運行?” 或 “我們的聯繫人電子郵件表單是否工作?”。

除了上述這些類別,我所遇到或見過的指示板還常常具有一些共性,比如它們多久更新一次,它們展示的是定量數據、定性數據還是二者都展示 — 有一些頗值得我們進行細緻研究。

KPI 的例子

如下所列的是一些 KPI 的例子,它們很可能正適合您公司的業務需求:

  • Web 站點:點擊量、訪客數量、訪問時長
  • 技術支持:對技術支持的請求量、客戶滿意度、通話時長
  • 人力資源 (HR):員工流動情況、空缺職位的數量、待定的績效評估的數量
  • 信息技術 (IT):系統宕機時間、網路性能、bug 解決的情況
  • 銷售:預計的銷售、訂單數量、收款
  • 市場:顧客統計、活動成效、市場份額
  • 財務:利潤、成本、收入

好的 KPI 是什麼樣的?

指示板傾向於顯示可度量的一些指標,在商界通常就是指所謂的關鍵績效指標(KPI)。一個 KPI 指的是能表明公司業務處理狀況的任何可測指標。因此,一個好的 KPI 應該能夠很好地度量公司內的任何戰略、分析或操作目標的成功或失敗。

側欄 “KPI 的例子” 給出了您的公司可以採用的幾個 KPI 例子。實際上,這些 KPI 對很多公司都是適用的:我鼓勵尋找(正如在之前的記分板示例中那樣)能簡便地展現業務處理狀況特徵的一個 KPI。KPI 越是接近您公司的具體業務,指標就越合適。

請務必注意 KPI 的定義有可能會不斷變化,因為隨著時間和經驗的積累您會掌握更合適的定義它們的方法,以及用它們所想要回答的問題。畢竟,使用 KPI 的最終目的還是提出並解答有關您業務情況的這些問題。

除此之外,無須害怕 KPI:它可以很高深,也可以很簡單,這取決於您的選擇,而且現在 Web 上有大量的參考資源可幫助您打造出自己的 KPI。我認為在創建 KPI 過程中最重要的一件事情就是確保有數據可用。

好的指示板是什麼樣的?

一個好的 Web 指示板總是力求以最簡明的方式呈現這些 KPI,它最大化數據,並儘可能地減少與信息表達無關的圖形 “噪音”。按照戰略、操作和分析目標來組織這些顯示元素是個很好的做法。在對想要進行對比的條目進行分組時,需要檢查對比是否相關、有效並且這個對比提供了對業務的一些有用反饋,而不是解釋過去發生的事情。雖然解釋過去發生的某個事情可以算是一種服務,但是指示板的任務是給出事情現在和當前的狀態。如果需要歷史記錄來更好地了解現狀,可以讓所構建的指示板或其數據能夠定期地被保存。

若一個指示板在一開始就以最為簡要的格式顯示數據,而後又大肆顯示更多的信息,它很容易就會變成一個瀏覽信息的工具。即便您的確提供了像數據向下鑽取或導航 UI 之類的元素,還是需要將此指示板與特定的用戶角色相匹配。最佳的做法是讓一個指示板對應於一個特定的角色。

最後,一個好的 Web 指示板會避開過於精細的圖片。典型的例子是使用類似三維 (3D) 餅圖這樣的圖形,其實,額外的深度反倒會讓可視地決定各個塊在整個圖形中所佔的比例變得更為困難。更甚者,現在,已經有很多討論(更多信息,請參見 參考資料)共同反對使用這種餅圖。

如果與我上面剛剛給出的這些建議背道而馳,那麼得到的就是一個糟糕的指示板。這裡,我列出了在設計得很糟糕的指示板應用程序中常見的幾個顯著特徵:

  • 過度使用顏色:基於顏色組織數據固然好,但是很多人還是有點走極端。
  • 要求用戶滾動或使用選項卡。讓用戶遍閱整頁的數據會讓用戶感到麻煩。
  • 過於詳細。不對信息進行總結會讓人無法綜合數據以採取實質的行動。
  • 過於精確。比如,數字內小數點位數太多或圖片上數據標籤太多。
  • 關鍵的異常遭忽視。不突出異常(比如偏離了某個目標或沒有達到某個目地)會消弱指示板在當前時間框架內調用動作的效用。
  • 部署的指標不全面或不完善。確保 KPI 得到恰當且準確地部署似乎很簡單,但 KPI 問題與之前的那些壞的特徵一樣時有發生。在將其安置到指示板應用程序之前,必須手動生成此指標或使用一個電子表格來進行一些示例計算的測試。

數據墨水(data ink)的基本理念蘊含著描述指示板好壞的另一種方式。作為信息和數據設計的一個基本原則,數據墨水 實際上是被列印頁面上代表數據(比如,數值或圖片上的數據線)的任何內容所用到的所有的墨水。計算機屏幕也是同樣的道理,其中數據像素類似於數據墨水,而其他的事情則不是。最大化信息設計內的數據像素意味著需要刪除盡量多的無關的圖形元素、使用低調的顏色模式並避免花哨的字體。





安裝示例指示板

在我向您展示如何構建這個示例指示板前,可以從 下載 部分獲得源文件並安裝這個指示板。為此,解壓縮 .zip 文件並遵循其中所包含的 README 文件的指導。

在安裝完畢后,應該能夠使用一個 Web 瀏覽器和如下的 URL 從 eXist 資料庫訪問 dashboard.xq 來查看這個示例指示板:

http://localhost:8080/exist/rest/db/dashboards_with_xquery/xquery/dashboard.xq

如果 XQuery 文件安裝在 eXist 的其他地方,可以相應調整這個 URL。

同樣應該注意這個示例指示板使用了很多測試數據和在線 Web 服務的憑證,所有這些均存在於 Internet 上。這些資源應該還可用,但是如果您遇到任何問題,我建議您用您自己的憑證和測試數據代替示例數據。





構建一個公司指示板

了解了指示板的原理,也知道了其主要目標就是以一種動人的方式展示 KPI 來幫助您提出並解答重要的業務問題,現在就可以開始創建這個示例指示板了。使用像 eXist XML 資料庫和 XQuery 這類 XML 技術就可以聚集和使用 XML 數據,然後再創建指示板的一個 HTML 表示。

圖 1 顯示了這個示例指示板的最終外觀。


圖 1. 示例指示板

這個 Web 頁面少有新奇的設計元素來吸引眼球,這是我遵循前面所提到的有關最大化數據像素建議的結果。這個 CSS 文件定義了一個顏色一般的背景色和一種很便於閱讀的字體。

我選擇了幾個現成的 KPI 來展示 XQuery 能夠多麼好地集成數據:

  • Aging Invoices:當一個公司收取其服務的費用時,費用通常是依照一套標準條款(例如,客戶付款的天數)收取的。
  • Sales Pipeline:一個公司常常在一系列階段之間對銷售機會進行分類,這定義了能夠最終成交並為此開帳單的可能性有多大。
  • Weekly Timesheets:顯示員工的周工作時間表,並能夠標示出每周工作時間超過 40 小時的員工。
  • Website Operation:這個監視指標表明 Web 站點是否在運轉。
  • Reminders:這是公司的工作任務的日程表。
  • Competitor Websites:這個圖表顯示了與競爭對手相比 Web 站點的性能如何。

指示板不太像是一個十分成熟的應用程序,它充分利用了 XQuery 的 eXist XML 資料庫實現中的特定功能。我們將要創建的這個指示板僅使用三個 XQuery 文件就可以實現,其中一個是供其他兩個文件使用的 XQuery 模塊,參見 圖 2。


圖 2. 指示板 XQuery 組件

utility.xqm XQuery 模塊包含 data.xq 與 dashboard.xq 所使用的一些函數。data.xq XQuery 文件的作用是生成一個包含所有與 KPI 相關的數據的 XML 文檔。dashboard.xq 則用來顯示數據,創建一個可以用瀏覽器查看的 HTML 文件。

首先是數據源

當我開發軟體時,首先要做的就是充實應用程序的數據層:如果一個有用的應用程序不 依靠數據,未免太不正常。在創建一個用來展示數據的指示板時,首先要做的自然就是確定數據源。

指示板的目標就是顯示 KPI,所以需要集成數據源,這些數據源可以是 KPI 本身,或者是與其計算相關的其他數據。不管 KPI 本質上是定性的還是定量的,所有的 KPI 都需要能夠展現出一些有關業務運轉的有用信息。以這個指示板示例為例,我使用了公開可用的數據來說明 XQuery 是如何處理集成場景的。此外,我還選用了與在內部、外部及業務周邊生成的 XML 數據有關的一系列流行的 Web 服務。

圖 3 中的圖表顯示了一組數據源,它們可以從 Google™ 之類流行的 Web 服務得到,也可以通過諸如關係資料庫這樣的常見技術獲得。


圖 3. 可用數據源的圖表

每種數據源都需要與一個 Web 服務、XML 數據或 XQuery 生成的數據相集成:

  • Website Operation:顯示 XQuery 本身就是一個易於擴展的語言
  • Aging Invoices:說明了如何從 XQuery 訪問 MySQL
  • Sales Pipeline:顯示了如何從 XQuery 訪問 Google Docs 電子數據表
  • Weekly Timesheets:顯示如何訪問一個本地的 Microsoft® Office Excel® 電子數據表
  • Reminders:與流行的 Backpack Web 服務集成
  • Competitor Web sites:一個圖表,它顯示了與競爭對手相比 Web 站點的性能如何

data.xq 的處理結果應是包含了所有所需數據的一個 XML 文檔。在 XQuery 內進行數據集成的最簡單的一個方法就是使用 doc() 函數,它可以從 Web URL 指向的站點檢索 XML。如果這個 URL 指向的是一個返回的數據結構不合法(從 XML 的角度來說)的資源,這時候再使用此函數就會得到一個錯誤。

清單 1 顯示了 data.xq 中的處理過程。


清單 1. data.xq 中的處理
				  <sales_pipeline desc="example accessing published Google spreadsheet">  {doc("http://spreadsheets.google.com/feeds/list/  pZDPqHJcLzxKntsQv2tuIMQ/1/public/basic")}  </sales_pipeline>    ...    <backpack desc="example accessing simple web service">  {doc("http://dashboardwithxquery.backpackit.com/  69babcbce8aa212fc83464088b45f7a97a9f3dce/reminders.xml")}  </backpack>  ...    <timesheet desc="example accessing local MS Excel file">  doc("file:///Users/jimfuller/Source/Writing/1_articles/1_ibm/  3_dashboards_with_xquery/working/src/data/MSOFFICE-timesheet.xls")  </timesheet>			  

sales_pipeline 元素訪問我發布的並可通過 URL 訪問的一個 Google 文檔。用這種方式,Google 文檔就可以作為 Atom XML 提要(相關鏈接,參見 參考資料)公開。Backpack URL 返回一個 XML 提要,它代表的是我在 URL http://www.backpackit.com 處設置的提醒(reminder)。timesheet 元素則不同,它負責訪問一個本地的 Excel 文件。幾年前,使用以特定於 Microsoft 的 XML 格式生成的 Excel 電子數據表也是可以的。

數據集成的下一個步驟就是使用 XQuery 創建一套幫助函數,它們均位於 utility.xqm XQuery 模塊中。以下是對這些函數的一個簡短介紹,並突出顯示了相關代碼:

  • utility:check_site():這一小段 XQuery 代碼用來檢查一個 Web URL 是否可被訪問以及 Web 伺服器做出響應要多長時間。清單 2 給出了這個函數。

    清單 2. utility:check_site() 函數
    						  declare function utility:check_site($uri) {   let $start := util:system-time()   let $response := httpclient:get(xs:anyURI($uri),false(),())   let $end := util:system-time()   let $response-time := (($end - $start) div xs:dayTimeDuration('PT1S')) * 1000   let $status-code := string($response/@statusCode)   return <test xmlns=""          ts="{current-dateTime()}"          status="{$status-code}"          response="{$response-time}" />   };   

    此函數返回的是一個測試元素,dashboard.xq 使用這個測試元素來顯示 Web 站點的狀態。

  • utility:get-aged-invoices():由於被編碼和存儲在關係資料庫中的數據的數量巨大,我們不妨來看一個集成 eXist XML 資料庫以便與 MySQL ® 社區伺服器交互的例子。XQuery 沒有內置的關係資料庫管理系統 (RDBMS) 的功能,但很多常見的 XQuery 處理器均有一些擴展函數。eXist XML 資料庫有 Structured Query Language (SQL) 擴展函數,這些函數以可選模塊的形式存在,所以必須通過 uncomment eXist conf.xml 文件內的恰當部分來啟用此模塊(參閱示例代碼內所包含的 README 文件)。清單 3 給出了這個 utility:get-aged-invoices() 函數。

    清單 3. utility:get-aged-invoices() 函數
    						  declare function utility:get-aged-invoices(){   let $connection := sql:get-connection("com.mysql.jdbc.Driver",  "jdbc:mysql://localhost/test", "root",  "")   let $data := sql:execute($connection, "select * from invoices;", fn:true())   return <invoices>  <total>{sum($data/sql:row/sql:invoice_amount)}</total>  <age	amt="15">      {sum($data/sql:row/sql:invoice_amount[../sql:invoice_terms='15'])}</age>  <age  amt="30">      {sum($data/sql:row/sql:invoice_amount[../sql:invoice_terms='30'])}</age>  <age  amt="60">      {sum($data/sql:row/sql:invoice_amount[../sql:invoice_terms='60'])}</age>  </invoices>   };   

    此函數先是使用 eXist SQL 擴展模塊的 sql:get-connection() 函數建立一個 Java™ Database Connectivity (JDBC)-風格的連接。然後,定義一個 SQL 語句來從這個資料庫選擇數據,此資料庫用 sql:execute 執行。此函數的結果保存在 $data 變數內,之後再使用它來通過 XPath 挑選相關數據。

如下所列的是一系列與各種 Google 的 Web 服務相集成的函數(更多信息,請參見 參考資料)。Google 的很多 Web 服務使用類似的技術來公開和連接它們,所以我特意給出了其中的幾個例子。(這些例子並沒有用在我們的這個示例指示板中,但它們可能對您很有啟發)。

  • utility:get-google-token($Email,$Passwd,$accountType,$source,$service):根據想要集成的深度,Google Web 服務提供了幾個不同的身份驗證機制。我選擇了它的 ClientToken 版本(如 清單 4 所示)來創建一次性的身份驗證 token,這適合於本例的目的。

    清單 4. Google utility:get-google-token($Email,$Passwd,$accountType,$source,$service) 服務
    						  declare function           utility:get-google-token($Email,$Passwd,$accountType,$source,$service){  let $params := concat("Email=",$Email,                        "&amp;Passwd=",$Passwd,                            "&amp;source=",$source,                            "&amp;accountType=",$accountType,                            "&amp;service=",$service)  let $uri := concat("https://www.google.com/accounts/ClientLogin?",$params)   let $response := httpclient:get(xs:anyURI($uri),false(),())   let $token := substring-after(xmldb:decode($response),"Auth=")   return          string($token)   };   

    請注意此函數返回的是一個字元串,而非 XML。在 XQuery,可以限制函數的輸入和輸出並給它們賦予一個數據類型。

  • utility:get-google-spreadsheet-feed($Email,$Passwd):此函數(如 清單 5 所示)從您自己(或他人)的 Google 文檔作為一個 Atom 提要返回 Google 文檔的一個列表。由於我使用的是一個公開可用的 Google 電子數據表,我猜想有些開發人員會非常想知道如何通過 XQuery 連接和使用 Google 文檔。

    清單 5. utility:get-google-spreadsheet-feed($Email,$Passwd) 函數
    						  declare function utility:get-google-spreadsheet-feed($Email,$Passwd){   let $accountType :=  "HOSTED_OR_GOOGLE"   let $source := "Dashboards-XQUERY-Example"   let $service := "wise"   let $token := utility:get-google-token($Email,$Passwd,$accountType,$source,$service)   let $headers := <headers> <header name="Authorization"  value="GoogleLogin auth={$token}"/>  </headers>   let $uri :=           xs:anyURI('http://spreadsheets.google.com/feeds/spreadsheets/private/full')  return           httpclient:get($uri, false(), $headers)   };   

    此函數製作了一個恰當的 HTTP 請求來檢索 Google 文檔內的文檔列表,這之後可被用來打開這些文檔。

  • utility:get-google-atom-feed():另一個有趣的數據源是 Google 的電子郵件地址。數據在 Gmail 內被作為 Atom 數據提要公開,如 清單 6 所示。(這個示例指示板並沒有真正地使用此數據源,但是在這裡將其作為處理電子郵件的數據源的例子給出,還是很有用的)。

    清單 6. utility:get-google-atom-feed() 函數
    						  declare function utility:get-google-atom-feed($user,$pass,$label){   let $token := util:string-to-binary(concat($user,':',$pass))   let $headers := <headers>   <header name="Authorization" value="Basic {$token}"/>   </headers>   let $uri := xs:anyURI(concat('https://mail.google.com/mail/feed/atom/',$label))  return   httpclient:get($uri, false(), $headers)   };   

  • utility:get-google-cal-feed($Email,$Passwd):另一個十分流行的 Google 服務是 Google Calendar(沒有用在 data.xq 內),用來顯示日曆事件數據。清單 7 給出了這個對應的函數。

    清單 7. utility:get-google-cal-feed($Email,$Passwd) 函數
    						  declare function utility:get-google-cal-feed($Email,$Passwd){   let $accountType := "HOSTED_OR_GOOGLE"   let $source := "Dashboards-XQUERY-Example"   let $service := "cl"   let $token := utility:get-google-token($Email,$Passwd,$accountType,$source,$service)  let $headers := <headers>   <header          name="GData-Version"           value="2"/>  <header name="Authorization"           value="GoogleLogin          auth={$token}"/>   </headers>   let $uri := xs:anyURI(          concat('http://www.google.com/calendar/feeds/',                          string($Email),                          '/private/full')          )  return   httpclient:get($uri, false(), $headers)   };   

這些函數被 data.xq 用來創建一個大型的 XML 文檔,該文檔就是這個數字指示板的源文檔。如果您已經安裝了代碼,我建議您通過瀏覽器訪問 data.xq,您應該能夠看到類似 圖 4 的結果。


圖 4. 檢索 data.xq

這個 markup 的結構是任意的,您可以自由選擇其他的方式。





指示板的表示

dashboard.xq XQuery 文件所生成的結果 — 一個 HTML 文檔 — 基於特定於 eXist XML 資料庫的序列化選項來表示這個指示板:

   declare option exist:serialize           "method=xhtml media-type=text/html indent=yes omit-xml-declaration=no";  

要創建這個示例指示板,用聚合后的這個 XML 文檔和 utility.xqm 內定義的這些 XQuery 函數構造這個 Web 頁面的各個特定區域,如 圖 5 所示。


圖 5. 將各函數對應到這個指示板

Google Charting API

http://chart.apis.google.com/chart?cht=bhs&chco=4D89F9,CCCCCC&chs=150x50&chl=0|100&chd=t:50 所示的條形圖是一個很好的展示如何使用 Google Charting API 動態生成條形圖的例子。上述這個條形圖使用了如下參數:

  • cht=bhs 是此圖的類型。
  • chco=4D89F9 是此圖的顏色。
  • chs=150x50 是此圖的大小。
  • chl=0|100 是此圖的標記。
  • chd=50 是此圖使用的數據。

關於 Google Charting API 的更多信息,請參見 參考資料。

KPI 是混合使用條形圖和 HTML 來顯示的,以給出特定指標的狀態。在使用條形圖的區域,我選擇了部署這個 Google Charting API。這個 API 創建了在 sales pipeline、aging invoices 和 time sheets 區域內用到的那些圖表:

  • Aging Invoices:通過使用代表標準付款期限(15、30 和 60 天)的三個獨立的條形圖顯示未付訂單的狀態。
  • Sales Pipeline:使用六個條形圖來表明在銷售流程的每個狀態各存在多少個潛在客戶。條形圖的範圍代表的是此渠道的各個階段的預期目標。
  • Timesheets:針對每個員工生成一個條形圖,如果員工每周工作超過 40 小時,條形就變成紅色。

為了便於創建這些圖表,我創建了一個 XQuery 函數 utility:graph(),此函數在 utility.xqm 內定義(參見 清單 8)。


清單 8. utility:graph() 函數
				  (: Wrap up Google Charting API :)   declare function utility:graph($type,$colors,$size,$markers,$data,$alt){   let $src           :=concat('http://chart.apis.google.com/chart?chf=bg,s,F7F5E6&amp;chco=',$colors,  '&amp;chs=',$size,  '&amp;cht=',$type,  '&amp;chl=',$markers,  '&amp;chd=t:',$data  )  return <img alt="{$alt}"src="{$src}"/>   };   

utility:graph() 函數構造這個 URL,返回結果為 img 元素。有關 Google Charting API 選項的更多信息,請參見 參考資料。

這個示例指示板需要數據才能完成特定的功能,所以接受了使用 doc() 函數由 data.xq 生成的聚合數據,並將結果保存在 $data 變數內:

let $data :=   doc('http://localhost:8080/exist/rest/db/dashboards_with_xquery/xquery/data.xq')   

將這個 XML 文檔放入 $data 變數意味著這些指標全部是同時測量的。這雖然不是很必要,但是它意味著所有的指標都是同步的 — 如希望定期保存結果和查看歷史性能的話,這一點十分有用。

隨後的清單描述了每個顯示區域並解釋了 XQuery 的主要工作原理。我用粗體 突出顯示了 XQuery 代碼以便讓其能夠從 HTML 標記中明顯地區分出來。

Aging Invoices

清單 9 中的 XQuery 代碼顯示了三個條形圖,但它們必須要統一以便於比較。由於所使用的範圍是 10,000,這意味著除數值也是這個值,然後再乘以 100 獲得在條形圖中所用的百分比。


清單 9. Aging Invoices 的條形圖代碼
				  <h3>Aging Invoices<sup>(mysql)</sup></h3>  <table>   <tr>  <td>£{$data/data/strategic/financial/invoices/age[@amt='15']}</td>  <td>  { let $amt :=(xs:float($data/data/strategic/financial/invoices/age[@amt='15'])           div 10000) * 100   return           utility:graph("bhs","4D89F9",                   "150x30", "0|10000",$amt, '15 day')  }   </td>   <td>15 Day</td> </tr>   <tr>  <td>£{$data/data/strategic/financial/invoices/age[@amt='30']}</td>          <td>{ let $amt :=  (xs:float($data/data/strategic/financial/invoices/age[@amt='30'])  div 10000) * 100   return           utility:graph("bhs",          "4D89F9",           "150x30",           "0|10000",          $amt,           '30 day')   } </td>   <td>30 Day</td> </tr>   <tr>  <td>£{$data/data/strategic/financial/invoices/age[@amt='60']}</td>  <td>{ let $amt := (xs:float($data/data/strategic/financial/invoices/age[@amt='60'])           div 10000) * 100   return   utility:graph("bhs","4D89F9", "150x30",           "0|10000", $amt, '60 day') } </td>  <td>60 Day</td> </tr>   </table>   

每個錶行都需要選擇正確的數據,這可以通過選擇 amt 屬性實現,該屬性代表的是總的數量。請記住此數據最初從 MySQL 資料庫生成,所以需要確保 MySQL 伺服器運行並由示例數據集載入。此外,還需要取消註釋這個 data.xq 代碼,正如 README 安裝指導文件內解釋的那樣。

Sales Pipeline

sales pipeline 數據從一個可公開查看的 Google Docs 電子數據表獲得。這意味著數據是從一個 Atom 提要中選擇 得到的。在呈現數據時惟一一個有些奇怪的地方是這個 Atom 提要(來自 Google 電子數據表)按行提供的數據內包含分隔符,如 清單 10 所示。


清單 10. Sales Pipeline 代碼
				  <h3>Sales Pipeline  <sup>(google spreadsheet)</sup></h3>  <table>   {for $item in $data/data/strategic/sales_pipeline/atom:feed/atom:entry/atom:content   return           let $cols := tokenize($item,',')           return   <tr>  <td>£{substring-after($cols[2],':')}</td>  <td>{   let $amt := (xs:float(substring-after($cols[2],':'))          div 10000) * 100 return  utility:graph("bhs",   "4D89F9,C6D9FD",  "150x30",   "0|10000",   $amt,  substring-after($cols[1],':'))   }</td>  <td>{  substring-after($cols[1],':')  }</td>  </tr> }  </table>   

XML 內包含分隔了的數據多少有些怪異,但 XQuery 提供了很多解析它的方法。我使用了 tokenize() 函數來分隔每列,然後再用 substring-after() 函數獲得這個數據值。

Weekly Timesheets

有的時候,獲得 timesheet 數據最好的方式就是打開一個本地的電子數據表。現在,Excel 已經支持 XML 格式,所以只需知道其結構就可以開始使用它了,如 清單 11 所示。


清單 11. 處理 Excel 電子數據表數據
				  <h3>Weekly Timesheets <sup>(MS Excel)</sup></h3>  <table> {  for $item in $data/data/operational/project/timesheet/  ss:Workbook/ss:Worksheet/ss:Table/ss:Row[not(position()=1)]  return   <tr> <td>{$item/ss:Cell[1]}</td>  <td>{$item/ss:Cell[2]}</td> <td>   {   let $hours := xs:decimal(($item/ss:Cell[3] div 40 ) * 100)   return          if ($hours &lt; 100) then                   utility:graph("bhs",                  "4D89F9,C6D9FD",                   "150x30",                  "0|40",                   $hours,                   $item/ss:Cell[3])                   else                  utility:graph("bhs",                   "FF5858,C6D9FD",                  "150x30",                   "0|40",                   $hours,                   $item/ss:Cell[3]) }  </td> </tr>   }  </table>  

XQuery 讓您避免使用第一行,因為該行包含了列標籤。另外一個需要實現的功能是當員工每周的工作時間超過 40 小時時,能讓條形圖顯示為紅色。 XQuery 內的 if|then|else 語句的作用是根據 $hours 變數的值是否大於 40 來選擇一個條形。

Microsoft 也開始提供基於開放標準的 XML 源代碼格式,這打破了很多年來一直使用二進位格式的局面。這些格式確實很巧妙,但並不開放,因此很難實現本文所示的這種集成。代表電子數據表的這個 Excel XML 格式是順理成章的,不過,有關其特定結構的優缺點,我留給別人去討論吧。

站點運行

由 data.xq 生成的測試元素能夠展現此 Web 站點是否在線以及需要多久 Web 伺服器才會響應。為了簡便起見,我只對 status 屬性運行了一個測試,如 清單 12 所示。


清單 12. 測試這個 Web 站點
				  <h3>Website Operation <sup>(xquery logic)</sup></h3>  <table> {  for $item in $data//website_ok/website   return           <tr>           <td>{$item/@title/string()}</td>  <td>   {   if ( $item/test/@status = '200' ) then          attribute style{'background-color:green'}   else   attribute style{'background-color:red'  }  } &#160;</td>  <td>{    $item/test/@response/string()    } ms</td>  </tr>   }  </table>  

使用類似的函數不僅能進行存在與否的測試,而且還能更近一步。比如,可以測試聯繫人表單是否工作。

Reminders

有了來自另外一個 Web 應用程序(http://www.backpackit.com/)的數據,我使用 XQuery FLWR(for、let、where 和 return)表達式對一個 XML Web 服務進行迭代,如 清單 13 所示。


清單 13. 對 XML Web 服務進行迭代
				  <h3>Reminders <sup>(simple webservice)</sup></h3> <table> {  for $item in $data/data/operational/project/backpack/reminders/reminder   	return  <tr>  <td>{  string($item/creator/@name)  }:</td>  <td>&#160;{  $item/content  }</td>  </tr>   }  </table>   





Competitor Website

為了啟發讀者,我還包括了一些額外的小部件。在這種意義上,一個指示板更像是由多種技術混合搭建起來的。compete.com Web 站點能很好地對比顯示幾個 Web 站點的性能。





結束語

在本文中,我構建了一個示例指示板,只是為了展示如何使用 XQuery,因此沒有創建一些快捷或高度可用的東西。如下是一些優化建議:

  • 通過調度 dashboard.xq 的執行來生成 dashboard.html, 使用 cron(和 wget 或 curl)。
  • 也可以使用 eXist XML 資料庫的調度程序來安排 dashboard.html 的創建。
  • 將來自每個數據源的結果單獨存儲於 XML 資料庫內。
  • 模塊化每個 KPI — 可以使用 XSLT 來管理數據的表示。

有了這三個直白的 XQuery 文件,您就可以實現一個能彰顯 XQuery 和 XML 在聚集和顯示數據方面的威力的 Web 指示板了。(責任編輯:A6)



[火星人 ] 用 XQuery 製作指示板已經有570次圍觀

http://coctec.com/docs/linux/show-post-68884.html