Xalan-C下數據庫擴展庫—Xalan-C_SQLExtLib實現

 

XSLT用來描述從一個XML文檔到另一個文檔的轉換規則(邏輯),Xalan-C爲XSLT的一個基於C++語言的解析器,根據XSLT所描述的轉換規則執行轉換。這非常類似腳本語言和腳本解釋器,可以理解爲XSLT就是一種腳本語言,而Xalan-C則是對應的腳本解釋器。

將轉換邏輯從代碼中分離出來,通過XSLT來是實現,從而可以大大提高程序的可複用性、可擴展性和靈活性。創建全新的或者修改現有的轉換業務,只需要編輯轉換規則腳本即可,無需修改和構建主程序。

然而,有時,Xalan-C提供的轉換規則(功能或者函數)是有限的,需要對其進行擴展。例如,在文檔轉換時,需要將原文檔中的商品類別編號輸出爲對應的商品類別名稱,而商品類別編號和名稱的對應關係存在數據庫的一張代碼表中。因此,需要在XSLT中描述從數據庫中獲取數據的轉換規則,並在Xalan-C中實現這種擴展腳本的功能,這就是本文的主題——Xalan-C下數據庫擴展庫的實現。

Xalan-C支持函數擴展,創建和使用用戶自定義函數,但不支持元素擴展。Xalan-J(Xalan的Java版本)支持元素擴展,且Xalan-J已經實現了一個SQL擴展,見http://xml.apache.org/xalan-j/extensionslib.html#sql

 

2.    Xalan-C實現自定義函數

2.1. 創建用戶自定義函數

用戶自定義函數需要繼承自Function基類

重載execute()方法,在該方法內實現函數功能,並且通過XObjectFactory工廠返回一個XSLT數據類型

重載clone()方法,允許Xalan創建和保持函數的一個副本

如果需要,隱藏賦值=和等於運算符方法。

// Base header file.  Must be first.

#include <xalanc/Include/PlatformDefinitions.hpp>

 

#include <cmath>

#include <ctime>

 

#include <xercesc/util/PlatformUtils.hpp>

#include <xalanc/XalanTransformer/XalanTransformer.hpp>

#include <xalanc/XPath/XObjectFactory.hpp>

 

XALAN_CPP_NAMESPACE_USE

 

// This class defines a function that will return the square root

// of its argument.

class FunctionSquareRoot : public Function

{

public:

 

  /**

   * Execute an XPath function object.  The function must return a valid

   * XObject.

   *

   * @param executionContext executing context

   * @param context          current context node

   * @param opPos            current op position

   * @param args             vector of pointers to XObject arguments

   * @return                 pointer to the result XObject

   */

  virtual XObjectPtr

  execute(

      XPathExecutionContext& executionContext,

      XalanNode* /* context */,

      const XObjectPtr arg,

          const Locator*       /* locator */) const

  {

    if (args.size() != 1)

    {

      executionContext.error("The square-root() function takes one argument!",

                              context);

    }

    assert(args[0] != 0);

    // Use the XObjectFactory createNumber() method to create an XObject

    // corresponding to the XSLT number data type.

    return executionContext.getXObjectFactory().createNumber(

                                                        sqrt(args[0]->num()));

  }

 

  /**

   * Implement clone() so Xalan can copy the square-root function into

   * its own function table.

   *

   * @return pointer to the new object

   */

// For compilers that do not support covariant return types,

// clone() must be declared to return the base type.

#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)

  virtual Function*

#else

  virtual FunctionSquareRoot*

#endif

  clone() const

  {

    return new FunctionSquareRoot(*this);

  }

 

private:

  // The assignment and equality operators are not implemented...

  FunctionSquareRoot&

  operator=(const FunctionSquareRoot&);

  bool

  operator==(const FunctionSquareRoot&) const;

}

 

2.2. 安裝、卸載用戶自定義函數

XalanTransformer類爲擴展函數提供安裝和卸載方法。

installExternalFunction在XalanTransformer的當前對象上安裝擴展函數。

uninstallExternalFunction在XalanTransformer的當前對象上卸載擴展函數。

installExternalFunctionGlobal在全局作用域上安裝擴展函數,

uninstallExternalFunctionGlobal在全局作用域上卸載擴展數據。

注意:如果擴展函數作爲全局函數安裝,那麼擴展函數應該是線程安全的。因爲多個線程可能同時調用同一個擴展函數。

 

2.3. 訪問用戶自定義函數

以下代碼片段安裝一個名稱爲“square-root”的本地函數FunctionSquareRoot(求平方根),並且綁定到命名空間http://MyExternalFunction.mycompany.org下。

#include <xalanc/Include/PlatformDefinitions.hpp>

#include <xercesc/util/PlatformUtils.hpp>

#include <xalanc/XalanTransformer/XalanTransformer.hpp>

// You have created a header file for FunctionSquareRoot.

#include <MyFunctions/FunctionSquareRoot.hpp>

// The namespace...

const XalanDOMString 

    theNamespace("http://MyExternalFunction.mycompany.org");

   

theXalanTransformer.installExternalFunction(theNamespace,

                                            XalanDOMString("square-root"),

                                            FunctionSquareRoot());

 

以下是使用擴展函數

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:external="http://ExternalFunction.xalan-c.xml.apache.org" exclude-result-prefixes="external">

       <xsl:template match="//area">

              <out>

     The area of the square is

     <xsl:value-of select="@value"/> square units.

     The length of each side is

     <xsl:value-of select="external:square-root(@value)"/> units

   </out>

       </xsl:template>

</xsl:stylesheet>

 

 

2.4. 其他

2.4.1. 字符串參數中帶有單引號

將含有單引號的字符串申明爲變量,然後,在函數調用時,使用變量。例如,

使用xpath的concat函數連接字符創“a’c’b”和“123”。

錯誤的語法如下:

<xsl:value-of select="concat('a'c'b','123')"></xsl:value-of>

正確的語法如下:

<xsl:variable name="var1">a'c'b</xsl:variable>

<xsl:value-of select="concat($var1,'123')"></xsl:value-of>

 

3.    Xalan-C_SQLExtLib

Xalan-C_SQLExtLib庫爲Xalan-C下的一個數據庫擴展函數庫,其特性如下:

l  採用ADO連接數據源,具有執行SQL語句及存儲過程的能力。

l  支持數據庫事務

l  支持多數據源訪問,支持同一個任務訪問不同數據源的能力。

l  提供數據庫連接池特性,按名訪問數據庫連接。

l  支持帶參數的SQL語句。

l  提供緩存和非緩存兩種模式。緩存模式下,一條查詢語句返回的結果集能夠多次使用,從而減少對數據庫的訪問,提供處理效率。

3.1. 安裝、卸載Xalan-C_SQLExtLib

Xalan-C_SQLExtLib.dll導出2個外部函數:

XalanSQLExtLib_Install:安裝SQL擴展庫

XalanSQLExtLib_UnInstall:卸載SQL擴展庫

宿主進程加載Xalan-C_SQLExtLib.dll,調用XalanSQLExtLib_Install安裝SQL擴展庫後即可使用SQL擴展庫提供的擴展函數。當不再需要使用時,調用XalanSQLExtLib_UnInstall卸載SQL擴展庫。

注意,部署時,將Xalan-C_SQLExtLib.dll與Xalan-C_1_10D.dll放在同一個目錄下。

3.2. 命名空間

http://Xalan-C_SQLExtLib.lijihongye.com

3.3. 擴展函數清單

Xalan-C_SQLExtLib擴展函數包括連接相關函數、查詢相關函數、執行SQL語句函數等。

註冊函數名

內部函數名

描述

連接相關函數

connect

XalanSQLExFunctionConnect

連接數據庫

disconnect

XalanSQLExFunctionDisconnect

關閉連接

查詢相關函數

query

XalanSQLExFunctionQuery

查詢

open-result-set

XalanSQLExFunctionOpenResultset

執行查詢,將結果集緩存

get-from-result-set

XalanSQLExFunctionGetFromResultset

從結果集中獲取數據

get-row-count-from-result-set

XalanSQLExFunctionGetRowCountFromResultset

返回結果集中記錄函數

get-col-count-from-result-set

XalanSQLExFunctionGetColCountFromResultset

返回結果集中列數

close-result-set

XalanSQLExFunctionCloseResultset

關閉結果集

事務相關函數

 

 

begin-transaction

XalanSQLExFunctionBeginTransaction

打開事務

commit-transaction

XalanSQLExFunctionCommitTransaction

提交事務

rollback-transaction

XalanSQLExFunctionRollbackTransaction

回滾事務

執行SQL語句函數

execute

XalanSQLExFunctionExecute

執行非查詢SQL語句

 

3.4. 連接相關函數

3.4.1. connect

connect函數創建一個新連接,並連接到數據源。

 

參數:

       參數1:ConnectName,連接名,字符串類型。

       參數2:ConnectString,連接字符串,字符串類型。

 

返回值:

       成功返回

       失敗返回

3.4.2. disconnect

disconnect函數斷開一個連接。

 

參數:

       參數1:ConnectName,連接名,字符串類型。

 

返回值:

       成功返回

       失敗返回

 

3.5. 查詢相關函數

3.5.1. query

query函數執行一條查詢語句,返回查詢結構集中第一行指定列的值。

 

參數:

參數1:QeuryColumnName,需查詢的列名,字符串類型。

參數2:ConnectName,連接名,字符串類型。

參數3:SQL,查詢SQL語句,字符串類型。

SQL參數能夠接受帶變量的SQL語句,變量沒有名字,沒有類型(都視爲字符串),只有位置(順序號),即第幾個(字符串)變量。變量用符號“?”表示,選擇“?”,是因爲該符號在SQL語句中不常出現。若SQL語句中本身含有“?”符號,不需要進行變量替換,則用“??”雙波浪號代替。在包含有變量的SQL語句調用中,變量的取值被跟隨在參數3後的參數給出,第i個變量取值爲第i+3個參數。原則上,有多少個變量,參數3後就應該有多少個參數。

      

返回值:

       如果查詢結果集爲空,返回“”空字符串;

       如果查詢結果集函數大於等於1行,則返回首行QeuryColumnName指定的列的值;

       如果SQL語句中的參數和實參個數不一致,則返回

       如果查詢語句非法,則返回

       如果查詢失敗,返回NF,。

       其他錯誤,返回

 

舉例:

不帶變量的query調用:在“laton”連接上執行“select maxobjectid from tb_0001”語句,並返回“maxobjectid”字段的值。

<out>

<xsl:value-of select="sqlextlib:query('code','laton',' select maxobjectid from tb_0001"/>

</out>

 

帶變量的query調用:在“laton”連接上執行“select code from tb_0002 where name=’?’”語句,其中where子句中“?”由XSLT參數$name替換並返回“code”列的值。

<out>

<xsl:param name="name" select="'test'"/>

<xsl:value-of select="sqlextlib:query('code','laton','select code from tb_0002 where name='?'',$name)"/>

</out>

 

3.5.2. open-result-set

query函數一次只能從查詢結果集中返回第一行中一個字段的值,若需要獲取同一條SQL語句中多個字段的值,則需要對同一SQL語句執行多次,效率低下。open-result-set函數執行一條查詢語句,並能緩存結果集,能用於get-from-result-set函數從結果集中多次獲取數據,直到close-result-set函數關閉結果集。

 

參數:

參數1:ResultsetName,結果集名,注意在同一個XSLT文件中不能定義2個相同的結果集。

參數2:ConnectName,連接名,字符串類型。

參數3:SQL,查詢SQL語句,同query函數的參數3。

      

返回值:

       如果函數執行成功,返回

       如果SQL語句中的參數和實參個數不一致,則返回

       如果查詢語句非法,則返回

       如果查詢失敗,返回NF,。

       其他錯誤,返回

      

open-result-set的實現需要考慮結果集的多實例問題。多實例問題可能出現在以下兩種場景中。第一種情況是同一個Xalan-C實例同時解析多個不同的XSLT文件,而這些文件中使用open-result-set函數打開了相同結果集,即ResultsetName參數相同;另一種情況則是同一個Xalan-C實例同時執行同一個包含有open-result-set函數的XSLT文件的多個轉換任務,例如同時將a.xml和b.xml通過同一個XSLT文件t.xsl轉換爲a.out和b.out。

       如果不考慮結果集多實例問題,則有可能導致SQL擴展庫混淆不同實例的結果集,張冠李戴,a.xml的結果集可能會被用於b.xml文件。

       解決這一問題的一個思路是結果集增加實例標示符屬性。實例標示符可以採用線程ID來進行唯一標示。該方案的一起缺陷即要求一個轉換任務需要在同一個線程中完成。

 

舉例:在“laton”連接上執行“select code,name from tb_0002”語句,並將查詢結果集緩存爲“CodeTable”。

<out>

<xsl:param name="RS_CodeTable" select="sqlextlib:open-result-set('RS_CodeTable','laton',' select code,name from tb_0002')"/>

</out>

 

3.5.3. get-from-result-set

get-from-result-set從open-result-set打開的結果集中獲取數據。

 

參數:

       參數1:ResultsetName,結果集名。

       參數2:Row,行號

       參數3:Col,列號

 

返回值:

       成功,返回

如果ResultsetName指定的結果集不存在,返回

如果Row行號越界,則返回

如果Col列號越界,則返回

 

舉例:

<out>

<xsl:param name="RS_CodeTable" select="sqlextlib:open-result-set('RS_CodeTable','laton',' select code,name from tb_0002')"/>

<xsl:value-of select="sqlextlib:get-from-result-set('RS_CodeTable',0,1)"/>

</out>

 

3.5.4. get-row-count-from-result-set

get-row-count-from-result-set返回結果集中記錄的函數。

 

參數:

       參數1:ResultsetName,結果集名。

 

返回值:

       成功,返回

如果ResultsetName指定的結果集不存在,返回

3.5.5. get-col-count-from-result-set

get-col-count-from-result-set返回結果集中列的個數。

 

參數:

       參數1:ResultsetName,結果集名。

 

返回值:

       成功,返回

如果ResultsetName指定的結果集不存在,返回

3.5.6. close-result-set

close-result-set關閉open-result-set打開的結果集。

參數:

       參數1:ResultsetName,結果集名。

 

返回值:

       成功,返回

如果ResultsetName指定的結果集不存在,返回

 

舉例:

<out>

<xsl:param name="RS_CodeTable" select="sqlextlib:open-result-set('RS_CodeTable','laton',' select code,name from tb_0002')"/>

<xsl:value-of select="sqlextlib:get-from-result-set('RS_CodeTable',0,1)"/>

<xsl:param name=" RS_CodeTable" select="sqlextlib:close-result-set('RS_CodeTable')"/>

</out>

 

3.6. 執行SQL語句函數

3.6.1. execute

execute函數執行一條SQL語句。

 

參數:

參數1:ConnectName,連接名,字符串類型。

參數2:SQL,SQL語句,參見query函數的參數3。

      

返回值:

       成功返回;

       若SQL語句中的參數和實參個數不一致,則返回

       若SQL語句非法,則返回

       其他錯誤,返回

4.    應用舉例

略。

 

參考文獻:

http://xml.apache.org/xalan-c/extensions.html

http://xml.apache.org/xalan-c/extensionslib.html

http://xml.apache.org/xalan-j/extensionslib.html#sql

 

 

 

發佈了71 篇原創文章 · 獲贊 9 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章