65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 XSLT 生成 SQL 脚本

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.20/5 (5投票s)

2010年2月27日

CPOL

3分钟阅读

viewsIcon

63262

downloadIcon

642

如何使用 XSLT 生成 SQL 脚本

情况

最近,我收到一项任务,需要检查 FilterConfig.xml 文件中配置的每个字段,以确保每个字段在 ScanConfig.xml 文件中配置的表或视图中都有相应的列名。

附注:FilterConfig.xml 用于我们系统中的过滤器模块,该模块基于 Web 控件 "SqlWhereBuilder"。(参考:https://codeproject.org.cn/KB/custom-controls/SqlWhereBuilder.aspx

如果某个字段在 FilterConfig.xml 文件中配置,但在相关表或视图中不存在,则配置或数据库架构肯定存在问题。

在深入研究这两个配置文件时,我发现每个字段都在 "Module" 节点下配置,并且每个模块在 ScanConfig.xml 中都有一个具有相同 ID 名称的相对 "Module" 节点,并且 "TableName" 也配置为该文件的 "Module" 节点的属性,“TableName” 显示数据库中的真实表名或视图名。

示例

  1. FilterConfig.xml
    <?xml version="1.0" encoding="utf-8"?>
    <FilterSchema>
     <Module ID="MasterInfo">
      <Field ID="ADDRESS1" Text ="Address" OperatorList ="datatype_text" />
      <Field ID="ADDRESS2" Text ="Address2" OperatorList ="datatype_text" />
      <Field ID="ADDRESSTYPE" Text ="Address Type" OperatorList ="datatype_text" />
     </Module>
    <FilterSchema>
  2. ScanConfig.xml
    <?xml version="1.0" encoding="utf-8"?>
    <ScanSchema>
     <Module ID="MasterInfo" TableName="VIEW_MASTER_INFO" 
         DataKeyName="ID" EnableDataKey="true" 
         OrderByFieldName="ID ASC" PageSize="5" 
         WhereClause="" MasterIdField="ID">
      <Field RealName="ID" ShownName="Master ID" 
              Width="33%" Align="left" />
      <Field RealName="COMPANY_NAME1" 
         ShownName="Company Name" Width="33%" 
         Align="left" />
      <Field RealName="FULL_NAME" ShownName="Sort Name" 
             Width="33%" Align="left" />
     </Module>
    </ScanSchema>

现在,如果我们能生成一个 SELECT 子句,其中包含 FilterConfig.xml 文件中配置的所有字段,然后在 SQL Server Management Studio 中运行该子句,我们将很容易发现是否存在任何问题。

根据上面的例子,生成的 SELECT 子句应该像这样

SELECT TOP(1) ADDRESS1, ADDRESS2, ADDRESSTYPE FROM VIEW_MASTER_INFO

到目前为止,看起来很容易,不是吗?但是,千万不要尝试手动生成 SELECT 子句,因为在 FilterConfig.xml 文件中配置了数百个模块和数千个字段。我们需要的是一种自动生成的方法来解决这个问题。这正是我要做的。

准备工作

首先,我很高兴介绍一个由 Riaan Hanekom 编写的有用工具,名为 "XSLT Tester"。它确实帮助我比使用 Internet Explorer 更快地预览结果。(参考:XSLT_Tester.aspx

_1__XSLT_Tester.jpg

解决方案

(1) 为了获取 TableName,我们需要合并两个文件 FilterConfig.xmlScanConfig.xml。它应该如下所示

<root>
 <FilterSchema>
  <Module ID="MasterInfo">
   <Field ID="ADDRESS1" Text ="Address" 
           OperatorList ="datatype_text" />
   <Field ID="ADDRESS2" Text ="Address2" 
           OperatorList ="datatype_text" />
   <Field ID="ADDRESSTYPE" Text ="Address Type" 
           OperatorList ="datatype_text" />
  </Module>
 </FilterSchema>
 <ScanSchema>
  <Module ID="MasterInfo" TableName="VIEW_MASTER_INFO" 
        DataKeyName="ID" EnableDataKey="true"
        OrderByFieldName="ID ASC" PageSize="5" 
        WhereClause="" MasterIdField="ID">
   <Field RealName="ID" ShownName="Master ID" 
        Width="33%" Align="left" />
   <Field RealName="COMPANY_NAME1" 
       ShownName="Company Name" Width="33%" 
       Align="left" />
   <Field RealName="FULL_NAME" ShownName="Sort Name" 
         Width="33%" Align="left" />
  </Module>
 </ScanSchema>
</root>

实际上,我们可以使用外部实体引用将这两个 XML 文件合并到新添加的父节点 <root></root> 中。

  1. integration.xml
    <?xml version="1.0"?>
    <?xml-stylesheet type="text/xsl" href="judge.xsl"?>
    <!DOCTYPE root [
     <!ENTITY claimer1 SYSTEM "./FilterConfig.xml">
     <!ENTITY claimer2 SYSTEM "./ScanConfig.xml">
    ]>

(2) 然后,我们编写 XSLT 文件。

  1. judge.xsl
    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0">
     <xsl:template match="/" name="TemplateA">
      <xsl:param name="param">
      </xsl:param>
      <xsl:value-of select="/root/ScanSchema/Module[@ID=$param]/@TableName"/>
     </xsl:template>
     <xsl:template match="/">
      <html>
       <title>
        Generated SQL Selecting Result
       </title>
       <body>
        <xsl:for-each select="/root/FilterSchema/Module">
         <br/>
         <![CDATA[SELECT TOP(1) ]]>
         <br/>
         <xsl:for-each select="./Field">
          <xsl:value-of select="@ID"/>
          <xsl:if test="position() &lt; last()">
           <xsl:text><![CDATA[,]]></xsl:text>
          </xsl:if>
          <xsl:if test="position()=last()">
           <xsl:text></xsl:text>
          </xsl:if>
          <br/>
         </xsl:for-each>
         <![CDATA[ FROM ]]>
         <xsl:call-template name="TemplateA">
          <xsl:with-param name="param" select="concat('&apos;,./@ID,&apos;')">
    	</xsl:with-param>
         </xsl:call-template><br/>
         <![CDATA[-----------------------------------------------]]>
         <br/>
        </xsl:for-each>
        <br/>
       </body>
      </html>
     </xsl:template>
    </xsl:stylesheet>
    1. 获取每个模块,并从模块中获取每个字段 ID。如果该字段不是最后一个字段,则在该字段 ID 之后添加逗号,如果遇到最后一个字段,则不添加任何内容。
    2. 对于每个模块,调用模板 "TemplateA" 以显示在 "/root/ScanSchema/Current Module" 节点内配置的相对 TableName。 使用 concat() string 与单引号连接起来。
    3. TemplateA 中,使用 <xsl:value-of> 元素选择 "/root/ScanSchema/Module[@ID=$param]/@TableName" 以显示 TableName

(3) 好吧,它将在瞬间完成。

现在,我们可以使用小型实用工具 "XSLT Tester" 或 Internet Explorer 来显示结果。

SELECT TOP(1) 
ADDRESS1,
ADDRESS2,
ADDRESSTYPE,
AUTHOR_EMAIL,
AUTHOR_FAX,
BUSINESS_CODE,
CATEGORY_NAME,
SOCIETY_CODE,
CITY,
CLASS,
COMPANYID,
COMPANY_NAME1,
COMPANY_SORT
FROM VIEW_MASTER_INFO

_2__XSLT_TESTER_RESULT_1.jpg

_3__IE_RESULT_2.jpg

然后复制并粘贴内容到您的 SQL Server Management Studio 并运行脚本。 如果您收到“成功”消息,则配置正常。

_4__SQL_SERVER_SUCCESS.jpg

结论

好吧,到现在为止,我已经完成了我的任务。根据当前的数据库架构,配置文件中总共有四个问题。 在脚本执行过程中,我发现如果超过 100 个 select 子句,SQL Server 将显示如下错误消息

"The query has exceeded the maximum number of result sets that can be displayed 
in the results grid. Only the first 100 result sets are displayed in the grid". 

如果您对此问题有更好的解决方案,请告诉我。 谢谢。

历史

  • 2010 年 2 月 27 日:首次发布
© . All rights reserved.