在SSIS的XML任务中使用/实现exsl函数node-set()

发布于 2024-07-23 12:06:19 字数 3525 浏览 3 评论 0原文

我正在尝试将 XSL 转换应用于 SSIS 包 XML 任务内的 XML 文件。

一切都很好,但不幸的是,我的 XSL 的“可移植性”比正常情况稍差一些,因为我需要使用函数 node-set()。 我的 XSL 的一个简化示例是:

<xsl:for-each select="msxsl:node-set($familyNames)/token">
  <xsl:call-template name="PersonNameComponent">
    <xsl:with-param name="nameComponentType" select="'S'" />
    <xsl:with-param name="nameComponentSeqNo" select="number($noOfGivenNames) + position()" />
    <xsl:with-param name="nameComponent" select="." />
    <xsl:with-param name="nameTypeName" select="$familyName" />
    <xsl:with-param name="roleCode" select="$roleCode" />
  </xsl:call-template>
</xsl:for-each>

我在样式表声明中使用以下命名空间:

xmlns:msxsl="urn:schemas-microsoft-com:xslt"

这适用于 VS IDE、XMLSpy(只要我将 XSLT 引擎设置为 MSXML)等。但是,当我尝试执行包中的 XML 任务出现以下异常:

错误:XML 任务处出现 0xC002F304,XML 任务:发生错误,并显示以下错误消息:“函数‘msxsl:node-set()’已失败。”。

我使用 VS2005 来设计包,因为它是 SSIS 的 2005 版本。

非常感谢任何有关我如何继续的想法。

我正在调用一个实现 EXSLT str:split 函数的模板,以将字符串“标记”为其组成元素,例如“Kermit T Frog”将返回如下:

<token>Kermit</token>
<token>T</token>
<token>Frog</token>

它存储在变量 $familyNames 中,然后我对其进行迭代通过。 但是,由于这是作为结果树片段返回的,因此我需要使用函数 msxsl:node-set() 来包装它,以便将结果视为节点集。 不知道我还能如何实现上述目标。

这是我从 http://www.exslt.org/ 获得的 str:split 的实现:

<xsl:template name="str:split">
    <xsl:param name="string" select="''" />
  <xsl:param name="pattern" select="' '" />
  <xsl:choose>
    <xsl:when test="not($string)" />
    <xsl:when test="not($pattern)">
      <xsl:call-template name="str:_split-characters">
        <xsl:with-param name="string" select="$string" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="str:_split-pattern">
        <xsl:with-param name="string" select="$string" />
        <xsl:with-param name="pattern" select="$pattern" />
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template> 
<xsl:template name="str:_split-characters">
  <xsl:param name="string" />
  <xsl:if test="$string">
    <token><xsl:value-of select="substring($string, 1, 1)" /></token>
    <xsl:call-template name="str:_split-characters">
      <xsl:with-param name="string" select="substring($string, 2)" />
    </xsl:call-template>
  </xsl:if>
</xsl:template> 
<xsl:template name="str:_split-pattern">
  <xsl:param name="string" />
  <xsl:param name="pattern" />
  <xsl:choose>
    <xsl:when test="contains($string, $pattern)">
      <xsl:if test="not(starts-with($string, $pattern))">
        <token><xsl:value-of select="substring-before($string, $pattern)" /></token>
      </xsl:if>
      <xsl:call-template name="str:_split-pattern">
        <xsl:with-param name="string" select="substring-after($string, $pattern)" />
        <xsl:with-param name="pattern" select="$pattern" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <token><xsl:value-of select="$string" /></token>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

I'm attempting to apply an XSL transform to an XML file inside an SSIS package XML Task.

All well and good, but unfortunately my XSL is slightly less "portable" than normal as I need to use the function node-set(). A simplified example of my XSL is:

<xsl:for-each select="msxsl:node-set($familyNames)/token">
  <xsl:call-template name="PersonNameComponent">
    <xsl:with-param name="nameComponentType" select="'S'" />
    <xsl:with-param name="nameComponentSeqNo" select="number($noOfGivenNames) + position()" />
    <xsl:with-param name="nameComponent" select="." />
    <xsl:with-param name="nameTypeName" select="$familyName" />
    <xsl:with-param name="roleCode" select="$roleCode" />
  </xsl:call-template>
</xsl:for-each>

I'm using the following namespace in the stylesheet declaration:

xmlns:msxsl="urn:schemas-microsoft-com:xslt"

This works in the VS IDE, XMLSpy (as long as I set the XSLT engine as MSXML), etc. However, when I attempt to execute an XML Task within the package I get the following exception:

Error: 0xC002F304 at XML Task, XML Task: An error occurred with the following error message: "Function 'msxsl:node-set()' has failed.".

I'm using VS2005 to design the package as it's the 2005 version of SSIS.

Any ideas on how I can proceed are greatly appreciated.

I'm calling a template that implements the EXSLT str:split function to"tokenise" a string into it's constituent elements, e.g. "Kermit T Frog" would be returned as follows:

<token>Kermit</token>
<token>T</token>
<token>Frog</token>

This is stored in the variable $familyNames, which I then iterate through. However, as this is returned as a result tree fragment I need to wrap it with the function msxsl:node-set() so that the result is treated as a node set. Not sure how else I can achieve the above.

Here's the implementation of str:split that I obtained from http://www.exslt.org/:

<xsl:template name="str:split">
    <xsl:param name="string" select="''" />
  <xsl:param name="pattern" select="' '" />
  <xsl:choose>
    <xsl:when test="not($string)" />
    <xsl:when test="not($pattern)">
      <xsl:call-template name="str:_split-characters">
        <xsl:with-param name="string" select="$string" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="str:_split-pattern">
        <xsl:with-param name="string" select="$string" />
        <xsl:with-param name="pattern" select="$pattern" />
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template> 
<xsl:template name="str:_split-characters">
  <xsl:param name="string" />
  <xsl:if test="$string">
    <token><xsl:value-of select="substring($string, 1, 1)" /></token>
    <xsl:call-template name="str:_split-characters">
      <xsl:with-param name="string" select="substring($string, 2)" />
    </xsl:call-template>
  </xsl:if>
</xsl:template> 
<xsl:template name="str:_split-pattern">
  <xsl:param name="string" />
  <xsl:param name="pattern" />
  <xsl:choose>
    <xsl:when test="contains($string, $pattern)">
      <xsl:if test="not(starts-with($string, $pattern))">
        <token><xsl:value-of select="substring-before($string, $pattern)" /></token>
      </xsl:if>
      <xsl:call-template name="str:_split-pattern">
        <xsl:with-param name="string" select="substring-after($string, $pattern)" />
        <xsl:with-param name="pattern" select="$pattern" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <token><xsl:value-of select="$string" /></token>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

逆光下的微笑 2024-07-30 12:06:19

我提出了一种解决方法,涉及使用自定义脚本任务而不是 XML 任务来转换 XML。 脚本任务中的代码是:

Imports System
Imports Microsoft.SqlServer.Dts.Runtime
Imports Mvp.Xml.Common.Xsl

Public Class ScriptMain

    ' The execution engine calls this method when the task executes.
    ' To access the object model, use the Dts object. Connections, variables, events,
    ' and logging features are available as static members of the Dts class.
    ' Before returning from this method, set the value of Dts.TaskResult to indicate success or failure.
    ' 
    ' To open Code and Text Editor Help, press F1.
    ' To open Object Browser, press Ctrl+Alt+J.

    Public Sub Main()

        Dts.TaskResult = Dts.Results.Failure

        If Dts.Variables.Contains("FullSourcePathFileName") AndAlso _
            Dts.Variables.Contains("XsltPath") AndAlso _
            Dts.Variables.Contains("FullSourceTransformedPathFileName") Then

            Dim input As String = CType(Dts.Variables("FullSourcePathFileName").Value, String)
            Dim xsl As String = CType(Dts.Variables("XsltPath").Value, String)
            Dim output As String = CType(Dts.Variables("FullSourceTransformedPathFileName").Value, String)

            Try
                Dim xslt As New MvpXslTransform()
                xslt.Load(xsl)
                xslt.Transform(New XmlInput(input), Nothing, New XmlOutput(output))

                Dts.TaskResult = Dts.Results.Success
            Catch ex As Exception
                Throw
                ' Look at logging, e.g. Dts.Logging.Log()
            End Try
        End If

    End Sub

End Class

我正在引用 Mvp.Xml 项目(可在 CodePlex 上获得)程序集,该程序集提供 EXSLT 函数的 .NET 实现。 作为额外的副作用,这意味着我可以从 xsl 中删除 str:split 模板实现。 我已将 Microsoft msxml 命名空间声明替换为以下内容:

xmlns:exsl="http://exslt.org/common"

直接调用 str:split 函数(无需将其存储在变量中)。

我知道的唯一含义是我需要将 Mvp.Xml 安装到将安装 SSIS 的服务器的 GAC 中(有关详细信息,请参阅 此处)。

I've come up with a work-around that involves using a custom Script Task instead of the XML Task to transform the XML. The code in the script task is:

Imports System
Imports Microsoft.SqlServer.Dts.Runtime
Imports Mvp.Xml.Common.Xsl

Public Class ScriptMain

    ' The execution engine calls this method when the task executes.
    ' To access the object model, use the Dts object. Connections, variables, events,
    ' and logging features are available as static members of the Dts class.
    ' Before returning from this method, set the value of Dts.TaskResult to indicate success or failure.
    ' 
    ' To open Code and Text Editor Help, press F1.
    ' To open Object Browser, press Ctrl+Alt+J.

    Public Sub Main()

        Dts.TaskResult = Dts.Results.Failure

        If Dts.Variables.Contains("FullSourcePathFileName") AndAlso _
            Dts.Variables.Contains("XsltPath") AndAlso _
            Dts.Variables.Contains("FullSourceTransformedPathFileName") Then

            Dim input As String = CType(Dts.Variables("FullSourcePathFileName").Value, String)
            Dim xsl As String = CType(Dts.Variables("XsltPath").Value, String)
            Dim output As String = CType(Dts.Variables("FullSourceTransformedPathFileName").Value, String)

            Try
                Dim xslt As New MvpXslTransform()
                xslt.Load(xsl)
                xslt.Transform(New XmlInput(input), Nothing, New XmlOutput(output))

                Dts.TaskResult = Dts.Results.Success
            Catch ex As Exception
                Throw
                ' Look at logging, e.g. Dts.Logging.Log()
            End Try
        End If

    End Sub

End Class

I'm referencing the Mvp.Xml project (available on CodePlex) assembly which provides a .NET implementation of the EXSLT functions. As a bonus side-effect this means I can remove the str:split template implementation from the xsl. I've replaced the Microsoft msxml namespace declaration with the following:

xmlns:exsl="http://exslt.org/common"

to call the str:split function directly (no need to store it in a variable).

The only implication I'm aware of is that I'll need to install Mvp.Xml into the GAC of the server that SSIS will be installed on (for details see here).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文