XSL - The variable or parameter '...' is either not defined or it is out of scope.

J

Jody Gelowitz

I have run into an issue with variable scope within an XSLT document that is translated in VS.NET 2.0. Under VS.NET 1.1 (XslTransform), this code works fine. However, when using VS.NET 2.0 (XslCompiledTransform), the exact same XSLT transformation fails with the error:

System.Xml.Xsl.XslLoadException: The variable or parameter 'lastrecordwaskit' was duplicated within the same scope. An error occurred at (174,12).
at System.Xml.Xsl.XslCompiledTransform.LoadInternal(Object stylesheet, XsltSettings settings, XmlResolver stylesheetResolver)
at System.Xml.Xsl.XslCompiledTransform.Load(XmlReader stylesheet)
at MyProject.MyClass.TranslateXML(String xsltFileName, String xmlText) in C:\Source\MySolution\MyProject\MyClass.vb:line 155


I have included the XSL code below which is related to the issue. In order to maintain the previous value of "iskit", I am declaring a variable "lastrecordwaskit" at the end of the loop. Near the beginning of the loop, prior to the variable declaration of "lastrecordwaskit", I am checking for "position() > 1" before trying to access "lastrecordwaskit". In .NET 1.1, this would allow the "lastrecordwaskit" variable to be declared prior to it being accessed. In .NET 2.0, it appears that this will no longer work.

I need to be able to access the previous value of a variable (or previous XML element) while inside of a loop. Are there any solutions to this problem with .NET 2.0?

Thanks,
Jody


<xsl:for-each select="Order/Invoice/InvoiceDetails/InvoiceDetail">

<xsl:variable name="iskit">

<xsl:choose>

<xsl:when test="@idt_set_master='N' and @idt_set_component_seq&gt;0">

1

</xsl:when>

<xsl:blush:therwise>

0

</xsl:blush:therwise>

</xsl:choose>

</xsl:variable>

<xsl:if test="position()&gt;1">

<xsl:if test="$lastrecordwaskit=1 and $iskit=0">

<tr>

<td>&nbsp;</td>

</tr>

</xsl:if>

</xsl:if>

{Additional Code ...}

<xsl:variable name="lastrecordwaskit"><xsl:value-of select="$iskit"/></xsl:variable>

</xsl:for-each>
 
M

Martin Honnen

Jody Gelowitz wrote:

<xsl:for-each select="Order/Invoice/InvoiceDetails/InvoiceDetail">

<xsl:variable name="iskit">

<xsl:choose>

<xsl:when test="@idt_set_master='N' and
@idt_set_component_seq&gt;0">

1

</xsl:when>

<xsl:blush:therwise>

0

</xsl:blush:therwise>

</xsl:choose>

</xsl:variable>

<xsl:if test="position()&gt;1">

<xsl:if test="$lastrecordwaskit=1 and $iskit=0">

<tr>

<td>&nbsp;</td>

</tr>

</xsl:if>

</xsl:if>

{Additional Code ...}

<xsl:variable name="lastrecordwaskit">

That variable is not in scope for the above xsl:if as it is a sibling
node of the xsl:if but would need to be defined in an ancestor of the
xsl:if to be in scope.
 
J

Jody Gelowitz

By using the XslTransform object (TranslateXML function), I was able to get this working in .NET 2.0. TranslateXML20 is the function that did not work with using XslCompiledTransform. I have attached the code for both versions.

Jody


Private Function TranslateXML(ByVal xsltFileName As String, ByVal xmlText As String) As String

Dim xst As System.Xml.Xsl.XslTransform = Nothing

Dim xal As System.Xml.Xsl.XsltArgumentList = Nothing

Dim xtr As System.Xml.XmlTextReader = Nothing

Dim resolver As System.Xml.XmlUrlResolver = Nothing

Dim xsltExt As XSLTExtension = Nothing

Dim xtrIn As System.Xml.XmlTextReader = Nothing

Dim xpd As System.Xml.XPath.XPathDocument

Dim sw As StringWriterWithEncoding = Nothing

Dim strReturn As String = String.Empty

Try

'Setup the XSL Transform object

xtr = New System.Xml.XmlTextReader(xmlText, Xml.XmlNodeType.Document, Nothing)

xst = New System.Xml.Xsl.XslTransform

xst.Load(xsltFileName)

'Prepare the XML document to be transformed

xtrIn = New System.Xml.XmlTextReader(xmlText, Xml.XmlNodeType.Document, Nothing)

xpd = New System.Xml.XPath.XPathDocument(xtrIn)

'Prepare the output objects

'This prevents unprintable characters from being printed at the top of the resulting string

sw = New StringWriterWithEncoding(New System.Text.UTF8Encoding(False))

'Transform the XML document using the XSLT file and place the output in "sw"

resolver = New System.Xml.XmlUrlResolver

xal = New System.Xml.Xsl.XsltArgumentList

xsltExt = New XSLTExtension

xal.AddExtensionObject("urn:date-format", xsltExt)

xst.Transform(xpd, xal, sw, resolver)

strReturn = sw.ToString.Replace(" ", "&nbsp;") 'Replace the   character with &nbsp;

Catch ex As Exception

Dim strMessage As String

strMessage = "xsltFileName: " & xsltFileName & ControlChars.CrLf

strMessage &= "xmlText: " & ControlChars.CrLf & xmlText & ControlChars.CrLf

RaiseEvent Exception(Me, New EMailExceptionEventArgs(ex))

Finally

If Not xal Is Nothing Then

xal = Nothing

End If

If Not sw Is Nothing Then

sw.Close()

sw = Nothing

End If

If Not xtrIn Is Nothing Then

xtrIn.Close()

xtrIn = Nothing

End If

If Not xtr Is Nothing Then

xtr.Close()

xtr = Nothing

End If

End Try

Return strReturn

End Function



Private Function TranslateXML20(ByVal xsltFileName As String, ByVal xmlText As String) As String

Dim xst As System.Xml.Xsl.XslCompiledTransform = Nothing

Dim xtrXSLT As System.Xml.XmlTextReader = Nothing

Dim xal As System.Xml.Xsl.XsltArgumentList = Nothing

Dim resolver As System.Xml.XmlUrlResolver = Nothing

Dim xsltExt As XSLTExtension = Nothing

Dim xtrXML As System.Xml.XmlTextReader = Nothing

Dim xw As Xml.XmlTextWriter = Nothing

Dim sw As StringWriterWithEncoding = Nothing

Dim strReturn As String = String.Empty

Try

'Create the XslTransform object and load the stylesheet

xst = New System.Xml.Xsl.XslCompiledTransform

xtrXSLT = New System.Xml.XmlTextReader(New IO.StreamReader(xsltFileName))

xtrXSLT.ProhibitDtd = False

xst.Load(xtrXSLT)

'Prepare the XML document to be transformed

xtrXML = New System.Xml.XmlTextReader(xmlText, Xml.XmlNodeType.Document, Nothing)

'Prepare the output objects

'This prevents unprintable characters from being printed at the top of the resulting string

sw = New StringWriterWithEncoding(New System.Text.UTF8Encoding(False))

xw = New Xml.XmlTextWriter(sw)

'Transform the XML document using the XSLT file and place the output in "sw"

resolver = New System.Xml.XmlUrlResolver

xal = New System.Xml.Xsl.XsltArgumentList

xsltExt = New XSLTExtension

xal.AddExtensionObject("urn:date-format", xsltExt)

xst.Transform(xtrXML, xal, xw, resolver)

strReturn = sw.ToString.Replace(" ", "&nbsp;") 'Replace the   character with &nbsp;

Catch ex As Exception

RaiseEvent Exception(Me, New EMailExceptionEventArgs(ex))

Finally

If Not xal Is Nothing Then

xal = Nothing

End If

If Not sw Is Nothing Then

sw.Close()

sw = Nothing

End If

If Not xw Is Nothing Then

xw.Close()

xw = Nothing

End If

If Not xtrXML Is Nothing Then

xtrXML.Close()

xtrXML = Nothing

End If

If Not xtrXSLT Is Nothing Then

xtrXSLT.Close()

xtrXSLT = Nothing

End If

End Try

Return strReturn

End Function



I have run into an issue with variable scope within an XSLT document that is translated in VS.NET 2.0. Under VS.NET 1.1 (XslTransform), this code works fine. However, when using VS.NET 2.0 (XslCompiledTransform), the exact same XSLT transformation fails with the error:

System.Xml.Xsl.XslLoadException: The variable or parameter 'lastrecordwaskit' was duplicated within the same scope. An error occurred at (174,12).
at System.Xml.Xsl.XslCompiledTransform.LoadInternal(Object stylesheet, XsltSettings settings, XmlResolver stylesheetResolver)
at System.Xml.Xsl.XslCompiledTransform.Load(XmlReader stylesheet)
at MyProject.MyClass.TranslateXML(String xsltFileName, String xmlText) in C:\Source\MySolution\MyProject\MyClass.vb:line 155


I have included the XSL code below which is related to the issue. In order to maintain the previous value of "iskit", I am declaring a variable "lastrecordwaskit" at the end of the loop. Near the beginning of the loop, prior to the variable declaration of "lastrecordwaskit", I am checking for "position() > 1" before trying to access "lastrecordwaskit". In .NET 1.1, this would allow the "lastrecordwaskit" variable to be declared prior to it being accessed. In .NET 2.0, it appears that this will no longer work.

I need to be able to access the previous value of a variable (or previous XML element) while inside of a loop. Are there any solutions to this problem with .NET 2.0?

Thanks,
Jody


<xsl:for-each select="Order/Invoice/InvoiceDetails/InvoiceDetail">

<xsl:variable name="iskit">

<xsl:choose>

<xsl:when test="@idt_set_master='N' and @idt_set_component_seq&gt;0">

1

</xsl:when>

<xsl:blush:therwise>

0

</xsl:blush:therwise>

</xsl:choose>

</xsl:variable>

<xsl:if test="position()&gt;1">

<xsl:if test="$lastrecordwaskit=1 and $iskit=0">

<tr>

<td>&nbsp;</td>

</tr>

</xsl:if>

</xsl:if>

{Additional Code ...}

<xsl:variable name="lastrecordwaskit"><xsl:value-of select="$iskit"/></xsl:variable>

</xsl:for-each>
 
J

Jody Gelowitz

I managed to get this working by changing the XslCompiledTransform object to
the old XslTransform object. For thoroughness, do you have an example of
where the variable should be declared? Currently, I have:

For Each
Declare "iskit"
If position > 1
If "lastrecordwaskit" Then
...
End If
End If
...
Declare "lastrecordwaskit" = "iskit"
Next


I get a duplicate declaration error if I try to declare "lastrecordwaskit"
outside of the For...Each loop.


Thanks,
Jody
 
M

Martin Honnen

Jody Gelowitz wrote:

For thoroughness, do you have an example of
where the variable should be declared? Currently, I have:

For Each
Declare "iskit"
If position > 1
If "lastrecordwaskit" Then
...
End If
End If
...
Declare "lastrecordwaskit" = "iskit"
Next

XSLT is not a procedural language, it is declarative and template based
so I don't think your attempts to write XSLT with VB pseudo code are
helpful to understand XSLT or to solve the problem.

I can't tell from the above what you are trying to achieve, how your XML
input looks so it is not possible to suggest an XSLT solution. You might
need a template taking parameters where you pass in the parameter as
needed and call the template again as needed. Or it might suffice to
look at the preceding sibling element and its attributes, not needing a
parameter or variable at all.
 
G

Guest

This is a bug in XslTransfom implementation. You should not rely on this bug
in production code.

Best regards,
Anton
 
Top