在 XSLT 中查询数据库并将结果应用于输出 XML

Querying database inside XSLT to and apply the result to output XML

我需要根据 ProductItemId 查询数据库并获取以下 XML 的 ProductName、ProductItemCode、ProductType 和 ActCode。我正在使用 SaxonEE 进行转换。查询应在 XSLT

内部触发

我的输入XML是:

<?xml version="1.0" encoding="UTF-8"?>
<ListOfSublines>
   <OrderSubline>
      <OrderSublineNumber>1</OrderSublineNumber>
      <OrderSublineType>ADD</OrderSublineType>
      <OrderlineInstance>120</OrderlineInstance>
      <Lob/>
      <Circle/>
      <Zone/>
      <ProductItem>
         <ProductItemId>10</ProductItemId>
         <AdditionalParams>
            <Parameter name="LOC_CODE" value="25"/>
            <Parameter name="LOC_DESC" value="Kolkata Circle"/>
         </AdditionalParams>
      </ProductItem>
   </OrderSubline>
   <OrderSubline>
      <OrderSublineNumber>2</OrderSublineNumber>
      <OrderSublineType>ADD</OrderSublineType>
      <OrderlineInstance>121</OrderlineInstance>
      <Lob/>
      <Circle/>
      <Zone/>
      <ProductItem>
         <ProductItemId>11</ProductItemId>
         <AdditionalParams>
            <Parameter name="PRODUCT_INDICATOR" value="Mobility Voice"/>
            <Parameter name="RATE CLASS" value="1"/>
            <Parameter name="RRCC" value="Bharti Tele-Ventures"/>
         </AdditionalParams>
      </ProductItem>
   </OrderSubline>
   <OrderSubline>
      <OrderSublineNumber>3</OrderSublineNumber>
      <OrderSublineType>ADD</OrderSublineType>
      <OrderlineInstance>122</OrderlineInstance>
      <Lob/>
      <Circle/>
      <Zone/>
      <ProductItem>
         <ProductItemId>12</ProductItemId>
         <AdditionalParams/>
      </ProductItem>
   </OrderSubline>

</ListOfSublines>

预期输出:

<?xml version="1.0" encoding="UTF-8"?>
    <ListOfSublines>
       <OrderSubline>
          <OrderSublineNumber>1</OrderSublineNumber>
          <OrderSublineType>ADD</OrderSublineType>
          <OrderlineInstance>120</OrderlineInstance>
          <Lob/>
          <Circle/>
          <Zone/>
          <ProductItem>
             <ProductItemId>10</ProductItemId>
             <ProductName>Value from Oracle Db based on ProductItemId 10</ProductName>
             <ProductItemCode>Value from Oracle Db</ProductItemCode>
             <ProductType>Value from Oracle Db</ProductType>
             <ActCode>Value from Oracle Db</ActCode>
             <AdditionalParams>
                <Parameter name="LOC_CODE" value="25"/>
                <Parameter name="LOC_DESC" value="Kolkata Circle"/>
             </AdditionalParams>
          </ProductItem>
       </OrderSubline>
       <OrderSubline>
          <OrderSublineNumber>2</OrderSublineNumber>
          <OrderSublineType>ADD</OrderSublineType>
          <OrderlineInstance>121</OrderlineInstance>
          <Lob/>
          <Circle/>
          <Zone/>
          <ProductItem>
             <ProductItemId>11</ProductItemId>
             <ProductName>Value from Oracle Db based on ProductItemId 11</ProductName>
             <ProductItemCode>Value from Oracle Db</ProductItemCode>
             <ProductType>Value from Oracle Db</ProductType>
             <ActCode>Value from Oracle Db</ActCode>
             <AdditionalParams>
                <Parameter name="PRODUCT_INDICATOR" value="Mobility Voice"/>
                <Parameter name="RATE CLASS" value="1"/>
                <Parameter name="RRCC" value="Bharti Tele-Ventures"/>
             </AdditionalParams>
          </ProductItem>
       </OrderSubline>
       <OrderSubline>
          <OrderSublineNumber>3</OrderSublineNumber>
          <OrderSublineType>ADD</OrderSublineType>
          <OrderlineInstance>122</OrderlineInstance>
          <Lob/>
          <Circle/>
          <Zone/>
          <ProductItem>
             <ProductItemId>12</ProductItemId>
             <ProductName>Value from Oracle Db based on ProductItemId 12</ProductName>
             <ProductItemCode>Value from Oracle Db</ProductItemCode>
             <ProductType>Value from Oracle Db</ProductType>
             <ActCode>Value from Oracle Db</ActCode>
             <AdditionalParams/>
          </ProductItem>
       </OrderSubline>

    </ListOfSublines>

您可以使用 Saxon 的 SQL 扩展(它完成了 80% 的人需要的 20% 的功能,但绝不是完整的),或者您可以使用 Java 扩展机制。

SQL 和 XSLT 都是 special-purpose 语言(共享声明类型的特征),旨在做一件特定的事情。对于 SQL 这通常意味着数据库操作或检索或 DDL and DML 过程,对于 XSLT 这意味着操作 XML 文档。

考虑使用通用语言,例如 Java(一种 Oracle 产品)、C#、Python、PHP、Perl、VB 甚至 R 和 SAS 以及还有一些可以处理您的 Oracle 数据库检索需求和 XML 文档解析和操作。此外,上述这些语言和其他语言为 XSLT 1.0 处理器维护它们自己的库,包括 XPath 1.0 和 XML DOM 文档库。更重要的是,这些语言可以通过命令行(线程或子进程)调用外部可执行文件,例如 Saxon EE,传递所需的参数,例如 xml 或 xslt 文档路径。最后,这些相同的语言维护 SQL ODBC/OLEDB api 库,包括 Oracle 数据库。顺便说一句,Oracle 在其 PL/SQL 方言中维护(与其他企业级 RDMS -SQL 服务器、PostgreSQL 一样)自己的 XML manipulation syntax and features

总而言之,根据您的需要,请考虑以下步骤:

  1. 选择熟悉的通用语言(上述或其他);
  2. 安装其必需的 Oracle 数据库连接器 API(即 Java 的 JDBC driver, Python 的 cx_Oracle、PHP 的 PDO DSN);
  3. 查询数据库 select 数据 SQL;
  4. 遍历查询数据以动态创建输入 XML 文档;
  5. 运行 XSLT 具有通用编码或最终 XML 输出的外部可执行文件;

感谢@Michael 的提示,我尝试了 SAXON SQL 扩展并能够查询数据库。

这是对我来说工作正常的 XSLT 代码:

    <xsl:transform version="2.0"
      exclude-result-prefixes="java saxon xsd xsi xsl"
      extension-element-prefixes="saxon sql"

      xmlns:java="http://saxon.sf.net/java-type"
      xmlns:saxon="http://saxon.sf.net/"
      xmlns:sql="java://net.sf.saxon.sql.SQLElementFactory"

      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

    >
<xsl:variable name="count" select="0" saxon:assignable="yes"/>
      <xsl:output method="xml" indent="yes"/>
      <xsl:preserve-space elements="*" />

      <xsl:param name="jdbc.driver"   as="xsd:string" select="'com.mysql.jdbc.Driver'" />

      <xsl:param name="jdbc.database" as="xsd:string" select="'jdbc:mysql://localhost:3306/test'" />

      <xsl:param name="jdbc.user" as="xsd:string" select="'root'" />
      <xsl:param name="jdbc.pass" as="xsd:string" select="'root'" />
      <xsl:template match="BOOKS">

            <xsl:variable name="sql.conn" as="java:java.sql.Connection">
              <sql:connect driver="{$jdbc.driver}" database="{$jdbc.database}" user="{$jdbc.user}" password="{$jdbc.pass}">
                <xsl:fallback>
                  <xsl:message terminate="yes">SQL extenstions are not installed</xsl:message>
                </xsl:fallback>
              </sql:connect>
            </xsl:variable>

    <xsl:for-each select="ITEM">
        <sql:insert connection="$sql.conn" table="book">
            <sql:column name="title" select="TITLE"/>
            <sql:column name="author" select="AUTHOR"/>
            <sql:column name="category" select="@CAT"/>
        </sql:insert>
        <saxon:assign name="count" select="$count+1"/> 
    </xsl:for-each>
<xsl:variable name="book-table">
    <sql:query connection="$sql.conn" table="book" column="*" row-tag="book" column-tag="col"/>
    </xsl:variable>

    <xsl:message>There are now <xsl:value-of select="count($book-table//book)"/> books.</xsl:message>
    <new-book-table>
        <xsl:copy-of select="$book-table"/>
    </new-book-table>

      </xsl:template>

    </xsl:transform>

希望对其他人有所帮助。