Xalan-C下数据库扩展库—Xalan-C_SQLExtLib实现

来源:互联网 发布:前台点击删除某条数据 编辑:程序博客网 时间:2024/05/16 15:53

 

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

 

 

 

原创粉丝点击