Использование / реализация exsl-функции node-set () в XML-задаче SSIS - PullRequest
0 голосов
/ 10 июня 2009

Я пытаюсь применить XSL-преобразование к файлу XML внутри задачи XML пакета SSIS.

Все хорошо, но, к сожалению, мой 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 в пакете, я получаю следующее исключение:

Ошибка: 0xC002F304 в задаче XML, задача 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 (), чтобы результат обрабатывался как набор узлов. Не уверен, как еще я могу достичь вышеуказанного.

Вот реализация str: split, которую я получил от 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>

1 Ответ

3 голосов
/ 16 июня 2009

Я придумал обходной путь, который включает использование пользовательской задачи сценария вместо задачи 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. В качестве дополнительного побочного эффекта это означает, что я могу удалить реализацию шаблона str: split из xsl. Я заменил объявление пространства имен Microsoft msxml следующим:

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

для непосредственного вызова функции str: split (нет необходимости сохранять ее в переменной).

Единственное, что мне известно, это то, что мне нужно установить Mvp.Xml в GAC сервера, на котором будет установлен SSIS (подробности см. здесь ).

...