home *** CD-ROM | disk | FTP | other *** search
/ ftp.tcs3.com / ftp.tcs3.com.tar / ftp.tcs3.com / DRIVERS / Audio / Office2010 / ProPlus.WW / ProPsWW.cab / RPT2HTM4.XSL < prev    next >
Extensible Markup Language  |  2009-07-29  |  67KB  |  1,988 lines

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:gen="#gen-functions" exclude-result-prefixes="msxsl gen">
  3.         <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" cdata-section-elements="msxsl:script" />
  4.     <ox:meta inputtype="ReportML" outputtype="HTML4WebRpt" displayname="HTML 4.0 Sample (XSL)" xmlns:ox="urn:schemas-microsoft-com:officexsl"/>
  5.  
  6.     <xsl:key name="Grouping" match="/RPTML/REPORT[1]/GROUP-LEVEL" use="GROUP-HEADER='true' or GROUP-FOOTER='true'" />
  7.     <xsl:template match="/">            
  8.         <xsl:value-of select="gen:CacheRPTML(.)" />
  9.         <xsl:value-of disable-output-escaping="yes" select="gen:StylesheetStart()" />
  10.             
  11. <!-- xsl:output element -->
  12.             <xsl:element name="xsl:output">
  13.                 <xsl:attribute name="method">html</xsl:attribute>
  14.                 <xsl:attribute name="version">4.0</xsl:attribute>
  15.                 <xsl:attribute name="indent">yes</xsl:attribute>
  16.             </xsl:element>
  17.             
  18. <!-- Add grouping keys -->
  19.             <xsl:for-each select="key('Grouping','true')">
  20.                 <xsl:element name="xsl:key">
  21.                     <xsl:attribute name="name"><xsl:value-of select="gen:GetGroupName(.)"/></xsl:attribute>
  22.                     <xsl:attribute name="match"><xsl:value-of select="../XML-RECORD-SOURCE"/></xsl:attribute>
  23.                     <xsl:attribute name="use"><xsl:value-of select="gen:GetGroupUse(.)"/></xsl:attribute>
  24.                 </xsl:element>
  25.             </xsl:for-each>
  26.  
  27. <!-- xsl:template element -->
  28.             <xsl:element name="xsl:template">
  29.                 <xsl:attribute name="match">//dataroot</xsl:attribute>
  30.                 <html>
  31.                     <xsl:if test="RPTML/REPORT[1]/DIR='right-to-left'">
  32.                         <xsl:attribute name="DIR">RTL</xsl:attribute>
  33.                     </xsl:if>
  34.                     <head>
  35.                         <META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=UTF-8"/>
  36.                         <title><xsl:value-of select="RPTML/REPORT[1]/TITLE"/></title>
  37. <!-- General styles -->    
  38.                         <style type="text/css">
  39.                             <xsl:apply-templates select="RPTML/REPORT[1]/STYLE"/>
  40.                         </style>
  41.                     </head>
  42.                         
  43. <!-- The BODY of the page -->
  44.                     <xsl:apply-templates select="RPTML/REPORT[1]"/>    
  45.                     
  46.                 </html>
  47.             </xsl:element>
  48.             
  49. <!-- Script used in output XSL -->    
  50.             <xsl:element name="msxsl:script" namespace="urn:schemas-microsoft-com:xslt">
  51.                 <xsl:attribute name="language">VBScript</xsl:attribute>
  52.                 <xsl:attribute name="implements-prefix">fx</xsl:attribute>                            
  53.     Option Explicit
  54.     
  55.     ' ********************************************************************************** 
  56.     ' **  Functions dynamically generated to evaluate expressions used as a Control Source   
  57.     ' ********************************************************************************** 
  58.     <xsl:call-template name="Expressions">
  59.         <xsl:with-param name="GlobalPrefix">gExpr_</xsl:with-param>
  60.         <xsl:with-param name="ExprNodes" select="/RPTML/REPORT[1]/SECTION/REPORT-ITEM[ENCODED-CONTROL-SOURCE/@type='expression' and not(RUNNING-SUM = 'over all' or RUNNING-SUM = 'over group')]" />
  61.     </xsl:call-template>
  62.     
  63.     ' ********************************************************************************** 
  64.     ' **  Functions dynamically generated to evaluate running sums 
  65.     ' ********************************************************************************** 
  66.     <xsl:call-template name="Expressions">
  67.         <xsl:with-param name="GlobalPrefix">gRunningSum_</xsl:with-param>
  68.         <xsl:with-param name="ExprNodes" select="/RPTML/REPORT[1]/SECTION/REPORT-ITEM[RUNNING-SUM = 'over all' or RUNNING-SUM = 'over group']" />
  69.     </xsl:call-template>
  70.  
  71. <xsl:for-each select="key('Grouping','true')">
  72.     <!-- Create CalculateExpressions_[Section] -->
  73.     <xsl:variable name="GroupID" select="@id" />
  74.     <xsl:call-template name="Calculations">
  75.         <xsl:with-param name="Section" select="../SECTION[@idref = $GroupID]" />
  76.         <xsl:with-param name="SectionName" select="$GroupID" />
  77.         <xsl:with-param name="SectionVBName"  select="gen:GenerateVBName(string(@id))" />
  78.         <xsl:with-param name="ResetRunningSums">true</xsl:with-param>
  79.         <xsl:with-param name="NextGroup"  select="position()+1" />
  80.     </xsl:call-template>    
  81. </xsl:for-each>
  82.  
  83.     <!-- Create CalculateExpressions_Detail -->
  84.     <xsl:call-template name="Calculations">
  85.         <xsl:with-param name="Section" select="/RPTML/REPORT[1]/SECTION[@type = 'detail']" />
  86.         <xsl:with-param name="SectionName">Detail</xsl:with-param>
  87.         <xsl:with-param name="SectionVBName">Detail</xsl:with-param>
  88.     </xsl:call-template>
  89.  
  90.     <!-- Create CalculateExpressions_Global -->
  91.     <xsl:call-template name="Calculations">
  92.         <xsl:with-param name="Section" select="/RPTML/REPORT[1]/SECTION[@type = 'report_header' or @type = 'page_header' or @type = 'page_footer' or @type = 'report_footer']" />
  93.         <xsl:with-param name="SectionName">Global</xsl:with-param>
  94.         <xsl:with-param name="SectionVBName">Global</xsl:with-param>
  95.     </xsl:call-template>
  96.  
  97.     ' ********************************************************************************** 
  98.     ' **  Functions dynamically generated to be used for sorting and grouping
  99.     ' ********************************************************************************** 
  100.     
  101. <xsl:for-each select="/RPTML/REPORT[1]/GROUP-LEVEL[ENCODED-CONTROL-SOURCE/@type='expression']">
  102.     ' This expression was <xsl:value-of select="ENCODED-CONTROL-SOURCE"/>
  103.     ' There is no formatting on Sorting/Grouping fields
  104.     Function GroupExpr_<xsl:value-of select="gen:GenerateVBName(string(@id))"/>(nodelist)
  105.         Set objCurrNodeT = objCurrNode
  106.         Set objCurrNode = nodelist.item(0)
  107.         
  108.         GroupExpr_<xsl:value-of select="gen:GenerateVBName(string(@id))"/> = <xsl:value-of select="gen:FixExpression(ENCODED-CONTROL-SOURCE, 1)" disable-output-escaping="yes"/>
  109.  
  110.         Set objCurrNode = objCurrNodeT
  111.     End Function
  112. </xsl:for-each>
  113.  
  114.     ' ********************************************************************************** 
  115.     ' **  Code staticly copied for expressions to use    
  116.     ' ********************************************************************************** 
  117.     
  118.     'variable declaration
  119.     Dim objCurrNode
  120.     Dim objCurrNodeT
  121.     Dim cGroupCount
  122.     Dim objGroupNodes
  123.  
  124.     Set objGroupNodes = Nothing
  125.     Set objCurrNode = Nothing
  126.     cGroupCount = 0
  127.     
  128.     Function PrepExpressions(CurrentNode, GroupNodes)        
  129.         CacheCurrentNode CurrentNode
  130.         CacheGroupNodes GroupNodes
  131.         PrepExpressions = ""
  132.     End Function
  133.     
  134.     Function CacheCurrentNode(objNodeList)        
  135.         Set objCurrNode = objNodeList.item(0)
  136.         CacheCurrentNode = ""
  137.     End Function
  138.     
  139.     Function CacheGroupNodes(objNodeList)
  140.         Set objGroupNodes = objNodeList
  141.         cGroupCount = objGroupNodes.length
  142.         CacheGroupNodes = ""
  143.     End Function
  144.  
  145.     Function GroupValue_quarter(strValue)
  146.         GroupValue_quarter = Left(strValue, 4) & DatePart("q", BuildDateFromStr(strValue, False))
  147.     End Function
  148.     
  149.     Function GroupValue_week(strValue)
  150.         GroupValue_week = Left(strValue, 4) & DatePart("ww", BuildDateFromStr(strValue, False))
  151.     End Function
  152.     
  153.     Function GroupValue_interval(nValue, nInterval)
  154.         GroupValue_interval = Int(nValue / nInterval)
  155.     End Function
  156.  
  157.     Function Page()
  158.         Page = 1
  159.     End Function
  160.     
  161.     Function Pages()
  162.         Pages = 1
  163.     End Function
  164.  
  165.     Function ToString(varValue)
  166.         On Error Resume Next
  167.         ToString = ""
  168.         ToString = CStr(varValue)
  169.     End Function
  170.  
  171.     Function ToNumber(varValue)
  172.         On Error Resume Next
  173.         ToNumber = 0
  174.         ToNumber = CDbl(varValue)
  175.     End Function
  176.     
  177.     Function FormatFromXSL(strRef, strFormat, iNumDecimals, LCID, nType)
  178.         FormatFromXSL = ToString(Format(GetValue(strRef, nType), strFormat, iNumDecimals, LCID, nType))
  179.     End Function
  180.  
  181.     Function Format(varValue, strFormat, iNumDecimals, LCID, nType)
  182.         Dim FormatTemp
  183.         Dim strTemp
  184.                                         
  185.         If IsDate(varValue) Then
  186.             Select Case strFormat
  187.                 Case "General Date"
  188.                     FormatTemp = FormatDateTime(varValue, vbGeneralDate)
  189.                 Case "Long Date"
  190.                     FormatTemp = FormatDateTime(varValue, vbLongDate)
  191.                 Case "Medium Date"
  192.                     If GetLocale = 1054 Then ' Special case for thai year
  193.                         FormatTemp = Day(varValue) & "-" & MonthName(Month(varValue), True) & "-" & Right(FormatDateTime(varValue, vbShortDate), 2)
  194.                     Else
  195.                         FormatTemp = Day(varValue) & "-" & MonthName(Month(varValue), True) & "-" & Mid(Year(varValue), 3, 2)
  196.                     End If
  197.                 Case "Short Date"
  198.                     FormatTemp = FormatDateTime(varValue, vbShortDate)
  199.                 Case "Long Time"
  200.                     FormatTemp = FormatDateTime(varValue, vbLongTime)                            
  201.                 Case "Medium Time"
  202.                     strTemp = FormatDateTime(varValue, vbLongTime)
  203.                     If (IsNumeric(Mid(strTemp, 2, 1))) Then
  204.                         FormatTemp = Mid(strTemp,1,5) & Mid(strTemp, 9)
  205.                     Else
  206.                         FormatTemp = Mid(strTemp,1,4) & Mid(strTemp, 9)
  207.                     End If
  208.                 Case "Short Time"
  209.                     FormatTemp = FormatDateTime(varValue, vbShortTime)
  210.                 Case Else
  211.                     Select Case LCase(strFormat)
  212.                         Case "yyyy", "q", "m", "y", "d", "w", "ww", "h", "n", "s"
  213.                             FormatTemp = DatePart(LCase(strFormat), varValue)
  214.                         Case Else
  215.                             ' This does not currently support custom formats such as dd-mmm-yyyy                                        
  216.                             FormatTemp = FormatDateTime(varValue, vbGeneralDate)
  217.                     End Select
  218.             End Select
  219.         ElseIf IsNumeric(varValue) Then
  220.             Select Case strFormat
  221.                 Case "General Number"
  222.                     FormatTemp = varValue
  223.                 Case "Currency"
  224.                     FormatTemp = FormatCurrencyPerLocale(varValue, iNumDecimals, LCID)
  225.                 Case "Euro"
  226.                     ' This does not really support the Euro format.
  227.                     FormatTemp = FormatCurrencyPerLocale(varValue, iNumDecimals, LCID)
  228.                 Case "Fixed"
  229.                     If IsNumeric(iNumDecimals) Then
  230.                         FormatTemp = FormatNumber(varValue, iNumDecimals, vbTrue, vbUseDefault, vbFalse)
  231.                     Else
  232.                         FormatTemp = FormatNumber(varValue, 2, vbTrue, vbUseDefault, vbFalse)
  233.                     End If
  234.                 Case "Standard"
  235.                     If IsNumeric(iNumDecimals) Then
  236.                         FormatTemp = FormatNumber(varValue, iNumDecimals, vbUseDefault, vbUseDefault, vbTrue)
  237.                     Else
  238.                         FormatTemp = FormatNumber(varValue, 2, vbUseDefault, vbUseDefault, vbTrue)
  239.                     End If
  240.                 Case "Percent"
  241.                     If IsNumeric(iNumDecimals) Then
  242.                         FormatTemp = FormatPercent(varValue, iNumDecimals)
  243.                     Else
  244.                         FormatTemp = FormatPercent(varValue)
  245.                     End If
  246.                 Case "Scientific"
  247.                     Dim nExp
  248.                     Dim nValue
  249.                     If (varValue = 0)  Then
  250.                         nExp = 0
  251.                     Else
  252.                               nExp = Int(Log(Abs(varValue)) / Log(10))
  253.                     End If
  254.                     nValue = Round(CDbl(varValue)/(10^CDbl(nExp)), 2)
  255.                     If (Sgn(nExp) < 0) Then
  256.                         FormatTemp = FormatNumber(nValue, 2, vbTrue, vbFalse, vbFalse) & "E" & nExp
  257.                     Else
  258.                         FormatTemp = FormatNumber(nValue, 2, vbTrue, vbFalse, vbFalse) & "E+" & nExp
  259.                     End If
  260.                 Case "True/False"
  261.                     If (CBool(varValue)) Then
  262.                         FormatTemp = "True"
  263.                     Else
  264.                         FormatTemp = "False"
  265.                     End If
  266.                 Case "Yes/No"
  267.                     If (CBool(varValue)) Then
  268.                         FormatTemp = "Yes"
  269.                     Else
  270.                         FormatTemp = "No"
  271.                     End If 
  272.                 Case "On/Off"
  273.                     If (CBool(varValue)) Then
  274.                         FormatTemp = "On"
  275.                     Else
  276.                         FormatTemp = "Off"
  277.                     End If 
  278.                 Case Else     ' This is a custom format                
  279.                     If nType = 6 Then ' This is a currency
  280.                         FormatTemp = FormatCurrencyPerLocale(varValue, iNumDecimals, LCID) 
  281.                     End If
  282.             End Select
  283.         End If
  284.  
  285.         If IsEmpty(FormatTemp) Then                                
  286.             FormatTemp = varValue
  287.         End If
  288.  
  289.         If FHasNoContent(FormatTemp) Then
  290.             Format = " "
  291.         Else
  292.             Format = FormatTemp
  293.         End If
  294.                         
  295.     End Function
  296.  
  297.     Function     FormatCurrencyPerLocale(varValue, iNumDecimals, LCID)
  298.         Dim CurrentLCID
  299.         If LCID >< "" Then    CurrentLCID = SetLocale(LCID)
  300.         If IsNumeric(iNumDecimals) Then
  301.             FormatCurrencyPerLocale = FormatCurrency(varValue, iNumDecimals)
  302.         Else
  303.             FormatCurrencyPerLocale = FormatCurrency(varValue)
  304.         End If
  305.         If Not IsEmpty(CurrentLCID) Then SetLocale CurrentLCID 
  306.     End Function
  307.     
  308.     Function FHasNoContent(objValue)
  309.         FHasNoContent = True
  310.         
  311.         If IsNull(objValue) Then Exit Function
  312.         If IsEmpty(objValue) Then Exit Function
  313.         If Not IsObject(objValue) Then 
  314.             If objValue = "" Then Exit Function
  315.         Else
  316.             If objValue Is Nothing Then Exit Function
  317.         End if
  318.  
  319.         FHasNoContent = False
  320.     End Function
  321.  
  322.     Function IIf(fCond, varTrue, varFalse)
  323.         If fCond Then
  324.             IIf = varTrue
  325.         Else
  326.             IIf = varFalse
  327.         End If
  328.     End Function
  329.  
  330.     Function Nz(varValue, varReplace)
  331.         If FHasNoContent(varValue) Then
  332.             Nz = varReplace
  333.         Else
  334.             Nz = varValue
  335.         End If
  336.     End Function
  337.  
  338.     Function Sum(strExpr)
  339.         Dim nSum, i
  340.  
  341.         nSum = 0
  342.         Set objCurrNodeT = objCurrNode
  343.  
  344.         For i = 0 To cGroupCount - 1
  345.             Set objCurrNode = objGroupNodes.item(i)    
  346.             nSum = nSum + ToNumber(Eval(strExpr))
  347.         Next
  348.                 
  349.         Set objCurrNode = objCurrNodeT
  350.         Sum = nSum
  351.     End Function
  352.     
  353.     Function Count(strExpr)
  354.         Dim nCount, i
  355.         
  356.         If strExpr = "*" Then
  357.             Count = cGroupCount
  358.             Exit Function
  359.         End If
  360.         
  361.         Set objCurrNodeT = objCurrNode
  362.         nCount = 0
  363.         For i = 0 To cGroupCount - 1
  364.             Set objCurrNode = objGroupNodes.item(i)    
  365.             If Not FHasNoContent(Eval(strExpr)) Then
  366.                 nCount = nCount + 1
  367.             End If    
  368.         Next
  369.  
  370.         Set objCurrNode = objCurrNodeT
  371.         Count = nCount
  372.     End Function
  373.         
  374.     Function Avg(strExpr)
  375.         Dim nSum
  376.         Dim nCount
  377.         nSum = Sum(strExpr)
  378.         nCount = Count(strExpr)
  379.         If nCount > 0 Then
  380.             Avg = nSum / nCount
  381.         Else
  382.             Avg = nSum
  383.         End If
  384.     End Function
  385.  
  386.     Function Min(strExpr)
  387.         Dim varMin, i
  388.         Dim varTemp
  389.         
  390.         Set objCurrNodeT = objCurrNode
  391.  
  392.         For i = 0 To cGroupCount - 1
  393.             Set objCurrNode = objGroupNodes.item(i)    
  394.             varTemp = Eval(strExpr)
  395.             If IsEmpty(varMin) Or (varTemp < varMin) Then
  396.                 varMin = varTemp
  397.             End If    
  398.         Next
  399.  
  400.         Set objCurrNode = objCurrNodeT
  401.         Min = varMin
  402.     End Function
  403.     
  404.     Function Max(strExpr)
  405.         Dim varMax, i
  406.         Dim varTemp
  407.     
  408.         varMax = Eval(strExpr)
  409.         Set objCurrNodeT = objCurrNode
  410.         
  411.         For i = 0 To cGroupCount - 1
  412.             Set objCurrNode = objGroupNodes.item(i)    
  413.             varTemp = Eval(strExpr)
  414.             If IsEmpty(varMax) Or (varTemp > varMax) Then
  415.                 varMax = varTemp
  416.             End If    
  417.         Next
  418.         
  419.         Set objCurrNode = objCurrNodeT
  420.         Max = varMax
  421.     End Function
  422.     
  423.     Function GetValue(strRef, nType)
  424.         ' Set Null as the default return value
  425.         GetValue = Null
  426.  
  427.         ' Return Null if anything goes wrong
  428.         On Error Resume Next
  429.     
  430.         Dim objNode
  431.         Set objNode = objCurrNode.selectSingleNode(strRef)
  432.         If (objNode Is Nothing) Or IsNull(objNode) Or IsEmpty(objNode) Or Not IsObject(objNode) Then
  433.             Exit Function
  434.         End If
  435.  
  436.         Dim CurrentLCID
  437.         CurrentLCID = SetLocale(1033)
  438.         
  439.         Select Case nType
  440.             Case 2             ' adSmallInt
  441.                 GetValue = CLng(objNode.text)
  442.  
  443.             Case 3         ' adInteger
  444.                 GetValue = CLng(objNode.text)
  445.  
  446.             Case 20        ' adBigInt
  447.                 GetValue = CLng(objNode.text)
  448.  
  449.             Case 17        ' adUnsignedTinyInt
  450.                 GetValue = CLng(objNode.text)
  451.  
  452.             Case 18        ' adUnsignedSmallInt
  453.                 GetValue = CLng(objNode.text)
  454.  
  455.             Case 19        ' adUnsignedInt
  456.                 GetValue = CLng(objNode.text)
  457.  
  458.             Case 21        ' adUnsignedBigInt
  459.                 GetValue = CLng(objNode.text)
  460.  
  461.             Case 4        ' adSingle
  462.                 GetValue = CDbl(objNode.text)
  463.  
  464.             Case 5        ' adDouble
  465.                 GetValue = CDbl(objNode.text)
  466.  
  467.             Case 6        ' adCurrency
  468.                 GetValue = CCur(objNode.text)
  469.  
  470.             Case 14        ' adDecimal
  471.                 GetValue = CDbl(objNode.text)
  472.  
  473.             Case 131        ' adNumeric
  474.                 GetValue = CDbl(objNode.text)
  475.  
  476.             Case 139        ' adVarNumeric
  477.                 GetValue = CDbl(objNode.text)
  478.  
  479.             Case 11        ' adBoolean
  480.                 GetValue = CBool(objNode.text)
  481.  
  482.             Case 7         ' adDate
  483.                 GetValue = BuildDateFromStr(objNode.text, True)
  484.  
  485.             Case 133        ' adDBDate
  486.                 GetValue = BuildDateFromStr(objNode.text, True)
  487.  
  488.             Case 134        ' adDBTime
  489.                 GetValue = BuildDateFromStr(objNode.text, True)
  490.  
  491.             Case 135        ' adDBTimeStamp
  492.                 GetValue = BuildDateFromStr(objNode.text, True)
  493.  
  494.             Case 8        ' adBSTR
  495.                 GetValue = objNode.text                
  496.  
  497.             Case 120        ' adChar
  498.                 GetValue = objNode.text                
  499.  
  500.             Case 200        ' adVarChar
  501.                 GetValue = objNode.text                
  502.  
  503.             Case 201        ' adLongVarChar
  504.                 GetValue = objNode.text                
  505.  
  506.             Case 130        ' adWChar:
  507.                 GetValue = objNode.text                
  508.  
  509.             Case 202        ' adVarWChar
  510.                 GetValue = objNode.text                
  511.  
  512.             Case 203        ' adLongVarWChar    
  513.                 GetValue = objNode.text        
  514.  
  515.             Case -7         ' Special value used to get just the date.
  516.                 GetValue = BuildDateFromStr(objNode.text, False)                
  517.  
  518.             Case Else
  519.                 GetValue = objNode.text                
  520.         End Select
  521.  
  522.         SetLocale CurrentLCID
  523.     End Function
  524.  
  525.     Dim gStaticDate
  526.     Function StaticDate()
  527.         If IsEmpty(gStaticDate) Then gStaticDate = GetValue("/*/@generated", -7)
  528.         StaticDate = gStaticDate
  529.     End Function
  530.  
  531.     Dim gStaticNow
  532.     Function StaticNow()
  533.         If IsEmpty(gStaticNow) Then gStaticNow = GetValue("/*/@generated", 7)
  534.         StaticNow = gStaticNow
  535.     End Function
  536.     
  537.     Function BuildDateFromStr(strDate, fIncludeTime)
  538.         Dim CurrentLCID
  539.         CurrentLCID = SetLocale(1033)
  540.         ' This requires that the Locale be set to en-us (1033).
  541.         BuildDateFromStr = CDate(Left(strDate,10))
  542.  
  543.         If (fIncludeTime) Then
  544.             BuildDateFromStr = BuildDateFromStr  + CDate(Right(strDate,8))
  545.         End If
  546.         SetLocale CurrentLCID
  547.     End Function
  548.  
  549.     Function ArrayItem(arr, index)
  550.         If index > UBound(arr) Then
  551.             ArrayItem = ""
  552.         Else
  553.             ArrayItem = arr(index)
  554.         End If
  555.     End Function
  556.  
  557.     Function HyperlinkPartFromNodeList(nodelist, nPart)
  558.         If nodelist.length = 0 Then
  559.             HyperlinkPartFromNodeList = ""
  560.         Else
  561.             HyperlinkPartFromNodeList = HyperlinkPartFromString(nodelist.item(0).text, nPart)
  562.         End If
  563.     End Function
  564.     
  565.     Function HyperlinkPart(strRef, nPart)
  566.         HyperlinkPart = HyperlinkPartFromString(GetValue(strRef, 200), nPart)
  567.     End Function
  568.     
  569.     Function HyperlinkPartFromString(strHyperlink, nPart)
  570.         Dim arrParts
  571.         Dim strHyperlinkPart
  572.         Dim strAddress, strSubAddress
  573.         
  574.         arrParts = Split(strHyperlink, "#")
  575.  
  576.         Select Case nPart
  577.             Case 0         ' acDisplayedValue
  578.                 strHyperlinkPart = ArrayItem(arrParts, 0)
  579.                 If strHyperlinkPart = "" Then
  580.                     strAddress = ArrayItem(arrParts, 1)
  581.                     strSubAddress = ArrayItem(arrParts, 2)
  582.  
  583.                     If strAddress = "" and strSubAddress = "" Then
  584.                         strHyperlinkPart = ""
  585.                     ElseIf strSubAddress = "" Then
  586.                         strHyperlinkPart = strAddress
  587.                     ElseIf strAddress = "" Then
  588.                         strHyperlinkPart = strSubAddress
  589.                     Else
  590.                         strHyperlinkPart = strAddress & " - " & strSubAddress
  591.                     End If
  592.                 End If
  593.             Case 1         ' acDisplayText
  594.                 strHyperlinkPart = ArrayItem(arrParts, 0)
  595.             Case 2         ' acAddress
  596.                 strHyperlinkPart = ArrayItem(arrParts, 1)
  597.             Case 3         ' acSubAddress
  598.                 strHyperlinkPart = ArrayItem(arrParts, 2)
  599.             Case 4         ' acScreenTip
  600.                 strHyperlinkPart = ArrayItem(arrParts, 3)
  601.             Case 5         ' acFullAddress
  602.                 strAddress = ArrayItem(arrParts, 1)
  603.                 strSubAddress = ArrayItem(arrParts, 2)
  604.                 
  605.                 If strAddress = "" and strSubAddress = "" Then
  606.                     strHyperlinkPart = "#"
  607.                 ElseIf strSubAddress = "" Then
  608.                     strHyperlinkPart = strAddress
  609.                 Else
  610.                     strHyperlinkPart = strAddress & "#" & strSubAddress
  611.                 End If
  612.         End Select
  613.         HyperlinkPartFromString = strHyperlinkPart
  614.     End Function
  615.             </xsl:element>
  616.         <xsl:value-of disable-output-escaping="yes" select="gen:StylesheetEnd()"/>
  617.     </xsl:template>
  618.  
  619. <!-- Expression template -->
  620.     <xsl:template name="Expressions">
  621.         <xsl:param name="GlobalPrefix" />
  622.         <xsl:param name="ExprNodes" />
  623.     <xsl:for-each select="$ExprNodes">
  624.     <xsl:variable name="VBName" select="gen:GenerateVBName(string(@id))" />
  625.  
  626.     ' [<xsl:value-of select="@id"/>] = <xsl:value-of select="ENCODED-CONTROL-SOURCE"/>
  627.     ' Format: "<xsl:value-of select="FORMAT"/>"
  628.     ' Decimal Places: "<xsl:value-of select="DECIMAL-PLACES"/>"
  629.     ' Running Sum: "<xsl:value-of select="RUNNING-SUM"/>"
  630.     Dim <xsl:value-of select="$GlobalPrefix"/><xsl:value-of select="$VBName"/>
  631.     Function ExprFromXSL_<xsl:value-of select="$VBName"/>()
  632.         ExprFromXSL_<xsl:value-of select="$VBName"/> = ToString(<xsl:value-of select="gen:AddFormatting('Format', concat($GlobalPrefix, $VBName), ENCODED-CONTROL-SOURCE)" disable-output-escaping="yes"/>)
  633.     End Function
  634.     </xsl:for-each>
  635.     </xsl:template>
  636.  
  637. <!-- Calculation template -->
  638.     <xsl:template name="Calculations">
  639.         <xsl:param name="Section" />
  640.         <xsl:param name="SectionName" />
  641.         <xsl:param name="SectionVBName" />
  642.         <xsl:param name="ResetRunningSums" />
  643.         <xsl:param name="NextGroup" />
  644.  
  645.     <xsl:if test="$ResetRunningSums">
  646.     ' This function will reset the sums for the <xsl:value-of select="$SectionName"/> section
  647.     Function ResetRunningSums_<xsl:value-of select="$SectionVBName"/>()
  648.     <xsl:choose>
  649.         <xsl:when test="key('Grouping','true')[$NextGroup]">
  650.             <xsl:for-each select="$Section/../SECTION[@idref = key('Grouping','true')[$NextGroup]/@id]/REPORT-ITEM[RUNNING-SUM = 'over group']">
  651.         gRunningSum_<xsl:value-of select="gen:GenerateVBName(string(@id))"/> = Empty
  652.             </xsl:for-each>
  653.         </xsl:when>
  654.         <xsl:otherwise>
  655.             <xsl:for-each select="$Section/../SECTION[@type = 'detail']/REPORT-ITEM[RUNNING-SUM = 'over group']">
  656.         gRunningSum_<xsl:value-of select="gen:GenerateVBName(string(@id))"/> = Empty
  657.             </xsl:for-each>
  658.         </xsl:otherwise>
  659.     </xsl:choose>
  660.         ResetRunningSums_<xsl:value-of select="$SectionVBName"/> = ""
  661.     End Function
  662.     </xsl:if>
  663.         
  664.     ' This function will calculate the running sums and expressions for the <xsl:value-of select="$SectionName"/> section
  665.     Function CalculateExpressions_<xsl:value-of select="$SectionVBName"/>(CurrentNode, GroupNodes)
  666.         PrepExpressions CurrentNode, GroupNodes
  667.         <xsl:if test="$ResetRunningSums">ResetRunningSums_<xsl:value-of select="$SectionVBName"/></xsl:if>
  668.         
  669.         On Error Resume Next
  670.     <xsl:for-each select="$Section/REPORT-ITEM[RUNNING-SUM = 'over group' or RUNNING-SUM = 'over all']">
  671.         <xsl:variable name="VBName" select="gen:GenerateVBName(string(@id))" />
  672.  
  673.         ' [<xsl:value-of select="@id"/>] = <xsl:value-of select="ENCODED-CONTROL-SOURCE"/>
  674.         gRunningSum_<xsl:value-of select="$VBName"/> = gRunningSum_<xsl:value-of select="$VBName"/> + <xsl:value-of select="gen:FixExpression(ENCODED-CONTROL-SOURCE, 0)" disable-output-escaping="yes"/>
  675.     </xsl:for-each>
  676.  
  677.     <xsl:for-each select="$Section/REPORT-ITEM[ENCODED-CONTROL-SOURCE/@type='expression' and not(RUNNING-SUM = 'over all' or RUNNING-SUM = 'over group')]">
  678.         <xsl:variable name="VBName" select="gen:GenerateVBName(string(@id))" />
  679.  
  680.         ' [<xsl:value-of select="@id"/>] = <xsl:value-of select="ENCODED-CONTROL-SOURCE"/>
  681.         gExpr_<xsl:value-of select="$VBName"/> = Empty
  682.         gExpr_<xsl:value-of select="$VBName"/> = <xsl:value-of select="gen:FixExpression(ENCODED-CONTROL-SOURCE, 1)" disable-output-escaping="yes"/>
  683.     </xsl:for-each>
  684.     
  685.         CalculateExpressions_<xsl:value-of select="$SectionVBName"/> = ""
  686.     End Function
  687.     </xsl:template>
  688.  
  689. <!-- style template -->
  690.     <xsl:template match="STYLE">
  691.         .<xsl:value-of select="@id"/> { <xsl:value-of select="gen:GetTextStyle(., false())"/> }
  692.     </xsl:template>
  693.  
  694. <!-- REPORT template -->
  695.     <xsl:template match="REPORT">
  696.  
  697. <!-- BODY element -->
  698.         <xsl:element name="body">
  699.             <xsl:attribute name="link"><xsl:value-of select="gen:GetNodeTextFromNodeList(., 'LINK', '#0000ff')"/></xsl:attribute>
  700.             <xsl:attribute name="vlink"><xsl:value-of select="gen:GetNodeTextFromNodeList(., 'VLINK', '#800080')"/></xsl:attribute>
  701.             <xsl:if test="BACKGROUND-IMAGE">
  702.                 <xsl:attribute name="style"><xsl:value-of select="gen:GetBodyStyle(.)"/></xsl:attribute>
  703.             </xsl:if>
  704.             <xsl:choose>
  705.                 <xsl:when test="XML-RECORD-SOURCE">
  706.                     <xsl:choose>
  707.                         <xsl:when test="LAYOUT='grid'">
  708. <!-- Table/Query scenario -->
  709.                             <table border="1" bgcolor="#ffffff" cellspacing="0" cellpadding="0">
  710.                                 <xsl:attribute name="id"><xsl:value-of select="gen:GetNextCtrlID()"/></xsl:attribute>
  711. <!-- COLGROUP element -->
  712.                                 <colgroup>
  713.                                         <xsl:apply-templates select="SECTION[@type='page_header']/REPORT-ITEM/COLUMN-WIDTH"/>
  714.                                 </colgroup>
  715. <!-- TBODY header element -->
  716.                                 <tbody>
  717.                                     <tr>
  718.                                         <xsl:apply-templates select="SECTION[@type='page_header']/REPORT-ITEM"/>
  719.                                     </tr>
  720.                                 </tbody>
  721. <!-- TBODY table element -->
  722.                                 <tbody>                                                                    
  723.                                     <xsl:attribute name="id"><xsl:value-of select="gen:GetNextCtrlID()"/></xsl:attribute>
  724.                                     <xsl:element name="xsl:for-each">
  725.                                         <xsl:attribute name="select"><xsl:value-of select="XML-RECORD-SOURCE"/></xsl:attribute>
  726.                                         <xsl:if test="SECTION[@type='detail']/REPORT-ITEM">
  727. <!-- Apply details section -->                                
  728.                                             <xsl:comment> Cache the current node incase the a field is formatted </xsl:comment>
  729.                                             <xsl:element name="xsl:value-of">
  730.                                                 <xsl:attribute name="select">fx:CacheCurrentNode(.)</xsl:attribute>
  731.                                             </xsl:element>    
  732.                                             <xsl:apply-templates select="SECTION[@type='detail']"/>
  733.                                         </xsl:if>
  734.                                     </xsl:element>
  735.                                 </tbody>
  736.                             </table>
  737.                         </xsl:when>
  738.                         <xsl:otherwise>
  739. <!-- Form/Report scenario -->
  740. <!-- Apply page & report headers -->
  741.                             <xsl:element name="xsl:variable">
  742.                                 <xsl:attribute name="name">GlobalGroup</xsl:attribute>
  743.                                 <xsl:attribute name="select"><xsl:value-of select="XML-RECORD-SOURCE"/></xsl:attribute>
  744.                             </xsl:element>
  745.                             <xsl:comment> Calculate expressions and running sums </xsl:comment>
  746.                             <xsl:element name="xsl:value-of">
  747.                                 <xsl:attribute name="select">fx:CalculateExpressions_Global($GlobalGroup[1], $GlobalGroup)</xsl:attribute>
  748.                             </xsl:element>                                
  749.  
  750.                             <xsl:apply-templates select="SECTION[@type='report_header']"/>
  751.                             <xsl:apply-templates select="SECTION[@type='page_header']"/>
  752.  
  753.                             <xsl:for-each select="key('Grouping','true')">
  754. <!-- Create grouping loops -->                            
  755.                                 <xsl:value-of disable-output-escaping="yes" select="gen:GetGroupForEachStart(.)" />
  756.                                 <xsl:comment> Calculate expressions and running sums </xsl:comment>
  757.                                 <xsl:element name="xsl:value-of">
  758.                                     <xsl:attribute name="select">fx:CalculateExpressions_<xsl:value-of select="gen:GenerateVBName(string(@id))"/>(., <xsl:value-of select="gen:GetGroupKey(.)"/>)</xsl:attribute>
  759.                                 </xsl:element>                                
  760.                                 
  761. <!-- Apply group headers -->                        
  762.                                 <xsl:apply-templates select="../SECTION[@type='group_header' and @idref=current()/@id]"/>
  763.                             </xsl:for-each>
  764.                                 
  765.                             <xsl:if test="SECTION[@type='detail']/REPORT-ITEM">
  766.                                 <xsl:attribute name="id"><xsl:value-of select="gen:GetNextCtrlID()"/></xsl:attribute>
  767.                                 <xsl:element name="xsl:for-each">
  768.                                     <xsl:choose>
  769.                                         <xsl:when  test="key('Grouping','true')">
  770.                                             <xsl:attribute name="select"><xsl:value-of select="gen:GetGroupKey(key('Grouping','true')[last()])"/></xsl:attribute>
  771.                                         </xsl:when>
  772.                                         <xsl:otherwise>
  773.                                             <xsl:attribute name="select"><xsl:value-of select="XML-RECORD-SOURCE"/></xsl:attribute>
  774.                                         </xsl:otherwise>
  775.                                     </xsl:choose>
  776.                                     <xsl:if test="GROUP-LEVEL">
  777.                                         <xsl:value-of disable-output-escaping="yes" select="gen:GetGroupSort(GROUP-LEVEL[last()])"/>
  778.                                     </xsl:if>
  779. <!-- Apply details section -->                    
  780.                                     <xsl:comment> Calculate expressions and running sums </xsl:comment>
  781.                                     <xsl:element name="xsl:value-of">
  782.                                         <xsl:attribute name="select">fx:CalculateExpressions_Detail(., $GlobalGroup)</xsl:attribute>
  783.                                     </xsl:element>                                
  784.                                     
  785.                                     <xsl:apply-templates select="SECTION[@type='detail']"/>
  786.                                 </xsl:element>                            
  787.                             </xsl:if>
  788.             
  789. <!-- This is done in reverse order because we are closing the groupings from last to first. -->
  790.                             <xsl:for-each select="key('Grouping','true')">
  791. <!-- Close grouping loops -->                            
  792.                                 <xsl:sort select="position()" order="descending" />
  793. <!-- Apply group footers -->                    
  794.                                 <xsl:comment> Prepare for any expressions in the group footer </xsl:comment>
  795.                                 <xsl:element name="xsl:value-of">
  796.                                     <xsl:attribute name="select">fx:PrepExpressions(., <xsl:value-of select="gen:GetGroupKey(.)"/>)</xsl:attribute>
  797.                                 </xsl:element>    
  798.                     
  799.                                 <xsl:apply-templates select="../SECTION[@type='group_footer' and @idref=current()/@id]"/>
  800.                                 <xsl:value-of disable-output-escaping="yes" select="gen:GetGroupForEachEnd(.)" />
  801.                             </xsl:for-each>
  802.                                 
  803. <!-- Apply page & report footers -->                            
  804.                             <xsl:comment> Prepare for any expressions in the report or page footer </xsl:comment>
  805.                             <xsl:element name="xsl:value-of">
  806.                                 <xsl:attribute name="select">fx:PrepExpressions($GlobalGroup[1], $GlobalGroup)</xsl:attribute>
  807.                             </xsl:element>    
  808.                             
  809.                             <xsl:apply-templates select="SECTION[@type='report_footer']"/>
  810.                             <xsl:apply-templates select="SECTION[@type='page_footer']"/>
  811.                         </xsl:otherwise>
  812.                     </xsl:choose>
  813.                 </xsl:when>
  814.                 <xsl:otherwise>
  815.                     <xsl:apply-templates select="SECTION[@type='report_header']"/>
  816.                     <xsl:apply-templates select="SECTION[@type='page_header']"/>
  817.                     <xsl:apply-templates select="SECTION[@type='report_footer']"/>
  818.                     <xsl:apply-templates select="SECTION[@type='page_footer']"/>
  819.                 </xsl:otherwise>
  820.             </xsl:choose>
  821.         </xsl:element>
  822.     </xsl:template>
  823.  
  824. <!-- SECTION templates -->
  825.     <xsl:template match="SECTION[../LAYOUT='absolute']">
  826.         <xsl:element name="div">
  827.             <xsl:attribute name="style"><xsl:value-of select="gen:GetTextStyle(., true)"/>; POSITION: relative</xsl:attribute>
  828.             <xsl:apply-templates select="REPORT-TEXT|REPORT-ITEM"/>
  829.         </xsl:element>
  830.     </xsl:template>
  831.  
  832.     <xsl:template match="SECTION[../LAYOUT='grid']">
  833.         <tr>
  834.             <xsl:apply-templates select="REPORT-TEXT|REPORT-ITEM"/>
  835.         </tr>
  836.     </xsl:template>
  837.  
  838. <!-- REPORT-TEXT template -->
  839.     <xsl:template match="REPORT-TEXT">
  840.         <xsl:value-of disable-output-escaping="yes" select="text()"/>
  841.     </xsl:template>
  842.  
  843. <!-- REPORT-ITEM templates -->
  844.     <xsl:template match="REPORT-ITEM[(@type='text-box' or @type='label' or @type='combo-box' or @type='list-box')]">
  845.         <xsl:choose>
  846.             <xsl:when test="../../LAYOUT='absolute'">
  847.                 <xsl:apply-templates select="ENCODED-CONTROL-SOURCE|CAPTION"/>
  848.             </xsl:when>
  849.             <xsl:when test="../../LAYOUT='grid'">
  850.                 <xsl:if test="../@type='page_header'">
  851.                     <td>
  852.                         <div align="center">
  853.                             <strong><xsl:value-of select="CAPTION" /></strong>
  854.                         </div>
  855.                     </td>
  856.                 </xsl:if>
  857.  
  858.                 <xsl:if test="../@type='detail'">
  859.                     <td>
  860.                         <xsl:apply-templates select="ENCODED-CONTROL-SOURCE"/>
  861.                     </td>
  862.                 </xsl:if>
  863.             </xsl:when>
  864.         </xsl:choose>
  865.     </xsl:template>
  866.     
  867.     <xsl:template match="REPORT-ITEM[@type='check-box']">
  868.         <xsl:element name="input">
  869.             <xsl:attribute name="type">checkbox</xsl:attribute>            
  870.             <xsl:attribute name="style"><xsl:value-of select="gen:GetCheckboxStyle(.)"/>; POSITION: absolute</xsl:attribute>
  871.             <xsl:element name="xsl:if">
  872.                 <xsl:attribute name="test"><xsl:value-of select="gen:GetCheckboxCondition(.)"/></xsl:attribute>
  873.                 <xsl:element name="xsl:attribute"><xsl:attribute name="name">checked</xsl:attribute></xsl:element>
  874.             </xsl:element>
  875.         </xsl:element>
  876.     </xsl:template>
  877.  
  878.     <xsl:template match="REPORT-ITEM[@type='line']">
  879.         <xsl:element name="hr">
  880.             <xsl:if test="@id"><xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute></xsl:if>
  881.             <xsl:if test="CLASS"><xsl:attribute name="class"><xsl:value-of select="CLASS"/></xsl:attribute></xsl:if>
  882.             <xsl:attribute name="style"><xsl:value-of select="gen:GetLineStyle(.)"/>; POSITION: absolute</xsl:attribute>
  883.         </xsl:element>
  884.     </xsl:template>
  885.  
  886.     <xsl:template match="REPORT-ITEM[@type='rectangle']">
  887.         <xsl:element name="div">
  888.             <xsl:if test="@id"><xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute></xsl:if>
  889.             <xsl:if test="CLASS"><xsl:attribute name="class"><xsl:value-of select="CLASS"/></xsl:attribute></xsl:if>
  890.             <xsl:attribute name="style"><xsl:value-of select="gen:GetRectangleStyle(.)"/>; POSITION: absolute</xsl:attribute>
  891.             <xsl:element name="xsl:value-of">
  892.                 <xsl:attribute name="disable-output-escaping">yes</xsl:attribute>
  893.                 <xsl:attribute name="select">' '</xsl:attribute>
  894.             </xsl:element>
  895.         </xsl:element>
  896.     </xsl:template>
  897.  
  898.     <xsl:template match="REPORT-ITEM[@type='image']">
  899.         <xsl:element name="IMG">
  900.             <xsl:if test="@id"><xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute></xsl:if>
  901.             <xsl:if test="CLASS"><xsl:attribute name="class"><xsl:value-of select="CLASS"/></xsl:attribute></xsl:if>
  902.             <xsl:attribute name="style"><xsl:value-of select="gen:GetImageStyle(.)"/>; POSITION: absolute</xsl:attribute>
  903.             <xsl:if test="SRC"><xsl:attribute name="SRC"><xsl:value-of select="SRC"/></xsl:attribute></xsl:if>
  904.         </xsl:element>
  905.     </xsl:template>
  906.  
  907. <!-- Do nothing templates -->
  908.     <xsl:template match="REPORT-ITEM[@type='button' or @type='radio-button' or @type='option-group' or @type='bound-object-frame' or @type='subform' or @type='chart' or @type='object-frame' or @type='page-break' or @type='activex-control' or @type='toggle-button' or @type='tab-control' or @type='tab-page' or @type='attachment-control']">
  909.     </xsl:template>
  910.  
  911.     <xsl:template match="ENCODED-CONTROL-SOURCE[text()!='']">
  912.         <xsl:variable name="nDataType" select="gen:GetDataType(string(../CONTROL-SOURCE))" />
  913.         <xsl:choose>
  914.             <xsl:when test="$nDataType=128 or $nDataType=204 or $nDataType=205">
  915.                 <xsl:element name="xsl:if">
  916.                     <xsl:attribute name="test"><xsl:value-of select="text()"/></xsl:attribute>
  917.                     [...]
  918.                 </xsl:element>
  919.             </xsl:when>
  920.             <xsl:when test="../../../LAYOUT='grid'">
  921.                 <xsl:call-template name="Control">
  922.                     <xsl:with-param name="argNode" select="." />
  923.                 </xsl:call-template>
  924.             </xsl:when>
  925.             <xsl:otherwise>
  926.                 <xsl:element name="span">
  927.                     <xsl:attribute name="class"><xsl:value-of select="../CLASS"/></xsl:attribute>
  928.                     <xsl:attribute name="style"><xsl:value-of select="gen:GetTextStyle(.., false())"/><xsl:if test="../CAN-GROW='false'">; OVERFLOW: hidden</xsl:if>; POSITION: absolute</xsl:attribute>
  929.                     <xsl:call-template name="Control">
  930.                         <xsl:with-param name="argNode" select="." />
  931.                     </xsl:call-template>
  932.                 </xsl:element>
  933.             </xsl:otherwise>
  934.         </xsl:choose>
  935.     </xsl:template>
  936.  
  937.     <xsl:template name="Control">
  938.         <xsl:param name="argNode" />
  939.         <xsl:choose>
  940.             <xsl:when test="$argNode/../BOUND-TO-HYPERLINK='true' or $argNode/../IS-HYPERLINK='true'">
  941.                 <xsl:variable name="HLinkName" select="concat('HLINK_', $argNode)"/>
  942.                 <xsl:element name="xsl:variable">
  943.                     <xsl:attribute name="name"><xsl:value-of select="$HLinkName"/></xsl:attribute>
  944.                     <xsl:attribute name="select">string(<xsl:value-of disable-output-escaping="no"  select="gen:ConvertControlSource($argNode)"/>)</xsl:attribute>
  945.                 </xsl:element>
  946.                 <xsl:element name="xsl:if">    
  947.                     <xsl:attribute name="test">string-length($<xsl:value-of select="$HLinkName"/>) > 0</xsl:attribute>
  948.                     <xsl:element name="a">
  949.                         <xsl:element name="xsl:attribute">
  950.                             <xsl:attribute name="name">href</xsl:attribute>
  951.                             <xsl:element name="xsl:value-of">        
  952.                                 <xsl:attribute name="select">fx:HyperlinkPartFromString($<xsl:value-of select="$HLinkName"/>, 5)</xsl:attribute>
  953.                             </xsl:element>
  954.                         </xsl:element>                            
  955.                         <xsl:element name="xsl:attribute">
  956.                             <xsl:attribute name="name">title</xsl:attribute>
  957.                             <xsl:element name="xsl:value-of">        
  958.                                 <xsl:attribute name="select">fx:HyperlinkPartFromString($<xsl:value-of select="$HLinkName"/>, 4)</xsl:attribute>
  959.                             </xsl:element>
  960.                         </xsl:element>    
  961.                         <xsl:element name="xsl:value-of">
  962.                             <xsl:attribute name="select">fx:HyperlinkPartFromString($<xsl:value-of select="$HLinkName"/>, 0)</xsl:attribute>
  963.                         </xsl:element>
  964.                     </xsl:element>
  965.                 </xsl:element>
  966.             </xsl:when>
  967.             <xsl:when test="$argNode/../TEXT-FORMAT='1'">
  968.                 <xsl:element name="xsl:value-of">
  969.                     <xsl:attribute name="select">
  970.                         <xsl:value-of disable-output-escaping="no"  select="gen:ConvertControlSource($argNode)"/>    
  971.                     </xsl:attribute>
  972.                     <xsl:attribute name="disable-output-escaping">yes</xsl:attribute>
  973.                 </xsl:element>
  974.             </xsl:when>
  975.             <xsl:otherwise>
  976.                 <xsl:element name="xsl:value-of">
  977.                     <xsl:attribute name="select">
  978.                         <xsl:value-of disable-output-escaping="no"  select="gen:ConvertControlSource($argNode)"/>    
  979.                     </xsl:attribute>
  980.                 </xsl:element>
  981.             </xsl:otherwise>
  982.         </xsl:choose>
  983.     </xsl:template>
  984.  
  985. <!-- CAPTION templates -->
  986.     <xsl:template match="CAPTION">
  987.         <xsl:element name="span">
  988.             <xsl:if test="../CLASS"><xsl:attribute name="class"><xsl:value-of select="../CLASS"/></xsl:attribute></xsl:if>
  989.             <xsl:attribute name="style"><xsl:value-of select="gen:GetTextStyle(.., false())"/>; OVERFLOW: hidden; POSITION: absolute</xsl:attribute>
  990.             <xsl:choose>
  991.                 <xsl:when test="../HREF">
  992.                     <xsl:element name="a">
  993.                         <xsl:attribute name="href"><xsl:value-of select="../HREF" /></xsl:attribute>
  994.                         <xsl:value-of select="text()" />
  995.                     </xsl:element>
  996.                 </xsl:when>
  997.                 <xsl:otherwise>
  998.                     <xsl:value-of select="text()" />
  999.                 </xsl:otherwise>
  1000.             </xsl:choose>
  1001.         </xsl:element>
  1002.     </xsl:template>
  1003.  
  1004. <!-- COLUMN-WIDTH templates -->
  1005.     <xsl:template match="COLUMN-WIDTH">
  1006.         <xsl:element name="col">
  1007.             <xsl:attribute name="style"><xsl:value-of select="gen:GetTextStyle(../../../SECTION[@type='detail']/REPORT-ITEM[@id=current()/../@parent], false())"/>WIDTH: <xsl:value-of select="text()" /></xsl:attribute>
  1008.         </xsl:element>
  1009.     </xsl:template>
  1010.  
  1011. <!-- Script used in this XSL -->    
  1012.     <msxsl:script language="JScript" implements-prefix="gen"  ><![CDATA[
  1013.  
  1014.         var gRPTML = null;
  1015.         function CacheRPTML(nodelist)
  1016.             {
  1017.             gRPTML = nodelist.item(0)
  1018.             return "";
  1019.             }
  1020.  
  1021.         function GetGroupNameFromNode(objGroup)
  1022.             {
  1023.             return GetNodeText(objGroup , "@id", "");
  1024.             }
  1025.                     
  1026.         function GetGroupName(nodelist)
  1027.             {
  1028.             var objGroup = nodelist.item(0);
  1029.             return GetGroupNameFromNode(objGroup);
  1030.             }            
  1031.             
  1032.         function GetGroupUse(nodelist)
  1033.             {
  1034.             var objGroup = nodelist.item(0);
  1035.             return GetGroupUseFromNode(objGroup);
  1036.             }
  1037.             
  1038.         function GetGroupUseFromNode(objGroup)
  1039.             {
  1040.             var prevGroup = GetPreviousGroup(objGroup);
  1041.             var strUse = GetGroupOnFromNode(objGroup);
  1042.  
  1043.             if (prevGroup == null)
  1044.                 return "string(" + strUse + ")";
  1045.                 
  1046.             while (prevGroup != null) 
  1047.                 {
  1048.                 strUse = GetGroupOnFromNode(prevGroup) + ", '-'," + strUse;
  1049.                 prevGroup = GetPreviousGroup(prevGroup);
  1050.                 }
  1051.             strUse = "concat(" + strUse + ")";
  1052.             return strUse;
  1053.             }
  1054.             
  1055.         function GetGroupOnFromNode(objGroup)
  1056.             {
  1057.             var strGroupOn = GetNodeText(objGroup, "GROUP-ON", "");
  1058.             var strInterval = GetNodeText(objGroup, "GROUP-INTERVAL", "");
  1059.             var strControlSource = ConvertControlSourceFromNode(objGroup.selectSingleNode("ENCODED-CONTROL-SOURCE"), true);
  1060.             
  1061.             switch (strGroupOn) 
  1062.                 {
  1063.                 case "each value":
  1064.                     return strControlSource;
  1065.                 case "prefix characters":
  1066.                     break;
  1067.                 case "year":
  1068.                     strInterval = "4";
  1069.                     break;
  1070.                 case "quarter":
  1071.                     return "fx:GroupValue_quarter(string(" + strControlSource + "))";
  1072.                 case "month":
  1073.                     strInterval = "7";
  1074.                     break;
  1075.                 case "week":
  1076.                     return "fx:GroupValue_week(string(" + strControlSource + "))";
  1077.                 case "day":
  1078.                     strInterval = "10";
  1079.                     break;
  1080.                 case "hour":
  1081.                     strInterval = "13";
  1082.                     break;
  1083.                 case "minute":
  1084.                     strInterval = "16";
  1085.                     break;
  1086.                 case "interval":
  1087.                     return "fx:GroupValue_interval(number(" + strControlSource + "), " + strInterval + ")";
  1088.                 }
  1089.             
  1090.             return "substring(" + strControlSource + ", 1, " + strInterval + ")";
  1091.             }
  1092.  
  1093.         function GetPreviousGroup(objGroup)
  1094.             {                
  1095.             var prevGroup = objGroup.previousSibling;
  1096.             while (prevGroup.nodeName == "GROUP-LEVEL") 
  1097.                 {
  1098.                 if (GetNodeText(prevGroup, "GROUP-HEADER", "") == "true" || GetNodeText(prevGroup, "GROUP-FOOTER", "") == "true") 
  1099.                     return prevGroup;
  1100.                 prevGroup = prevGroup.previousSibling;
  1101.                 }
  1102.             return null;
  1103.             }
  1104.  
  1105.         function GetGroupSort(nodelist)
  1106.             {
  1107.             return GetGroupSortFromNode(nodelist.item(0));
  1108.             }
  1109.         
  1110.         function GetGroupSortFromNode(objGroup)
  1111.             {
  1112.             var strSort = GetSingleGroupSortFromNode(objGroup);
  1113.             var prevGroup = objGroup.previousSibling;
  1114.             
  1115.             while (prevGroup.nodeName == "GROUP-LEVEL") 
  1116.                 {
  1117.                 if (GetNodeText(prevGroup, "GROUP-HEADER", "") == "true" || GetNodeText(prevGroup, "GROUP-FOOTER", "") == "true")  
  1118.                     break;
  1119.                 strSort = GetSingleGroupSortFromNode(prevGroup) + strSort;
  1120.                 prevGroup = prevGroup.previousSibling;
  1121.                 }
  1122.                 
  1123.             return strSort;
  1124.             }
  1125.                         
  1126.         function GetSingleGroupSortFromNode(objGroup)
  1127.             {
  1128.             var strSelect = " select=\"" + GetGroupOnFromNode(objGroup)  + "\"";            
  1129.             var strOrder = " order=\"" + GetNodeText(objGroup, "SORT-ORDER", "") + "\"";
  1130.  
  1131.             var strDataType = "";
  1132.             var strSource = GetNodeText(objGroup, "CONTROL-SOURCE", "");
  1133.             if (IsNumberType(GetDataType(strSource), true, true))
  1134.                 strDataType = " data-type=\"number\"";
  1135.             else
  1136.                 strDataType = " data-type=\"text\"";
  1137.  
  1138.             var strSort = "<xsl:sort" + strSelect + strOrder + strDataType +  " />\n";
  1139.             
  1140.             
  1141.             return strSort;
  1142.             }            
  1143.  
  1144.         function GetGroupKey(nodelist)
  1145.             {
  1146.             return GetGroupKeyFromNode(nodelist.item(0));
  1147.             }
  1148.  
  1149.         function GetGroupKeyFromNode(objGroup)
  1150.             {
  1151.             var strGroupName =  GetGroupNameFromNode(objGroup);
  1152.             var strControlSource = GetGroupUseFromNode(objGroup)
  1153.             return "key('" + strGroupName + "', " + strControlSource  + ")";
  1154.             }
  1155.         
  1156.         function GetGroupForEachStart(nodelist)
  1157.             {
  1158.             // e.g.     <xsl:for-each select="Invoices[count(. | key('Invoices-by-OrderID', OrderID)">
  1159.             
  1160.             var objGroup = nodelist.item(0);
  1161.             var prevGroup = GetPreviousGroup(objGroup);
  1162.  
  1163.             var strGroupName =  GetGroupName(nodelist);
  1164.             var objGroup = nodelist.item(0);
  1165.             var strRecordSource = "";
  1166.             
  1167.             if (prevGroup == null)
  1168.                 strRecordSource  = GetNodeText(objGroup , "../XML-RECORD-SOURCE", ""); 
  1169.             else
  1170.                 strRecordSource  = GetGroupKeyFromNode(prevGroup);
  1171.                 
  1172.             var strSelect = strRecordSource + "[count(. | " + GetGroupKeyFromNode(objGroup) + "[1]) = 1]";
  1173.             var strSort = GetGroupSort(nodelist);
  1174.             
  1175.             return  "\n<xsl:for-each select=\"" + strSelect + "\">\n" + strSort;
  1176.             }
  1177.             
  1178.         function GetGroupForEachEnd(nodelist)
  1179.             {
  1180.             return  "</xsl:for-each>";
  1181.             }
  1182.  
  1183.         function FixExpression(nodelist, replaceWithExpr)
  1184.             {
  1185.             var objElem = nodelist.item(0);
  1186.             return FixExpressionFromNode(objElem, replaceWithExpr==1);
  1187.             }
  1188.  
  1189.         var rgTotal = new Array("Sum", "Count", "Avg", "Min", "Max");
  1190.         
  1191.  
  1192.         function FixExpressionFromNode(objElem, fReplaceWithExpr)
  1193.             {
  1194.             var objNodes;
  1195.             var strExpr = objElem.text;
  1196.  
  1197.             //
  1198.             // Check for values that are not expressions such as running sums on controls that are not bound to expressions 
  1199.             //
  1200.             var strType = GetNodeText(objElem, "@type", "");
  1201.             if (strType != "expression")
  1202.                 strExpr = "[" + strExpr + "]";
  1203.  
  1204.  
  1205.             strExpr = FixInnerQuotes(strExpr);
  1206.  
  1207.             // Replace things like left$( with just left(
  1208.             strExpr = strExpr.replace(/\$\(/g, '(');
  1209.  
  1210.             // Replace Date() with StaticDate()
  1211.             strExpr = strExpr.replace(/date\(\)/gi, 'StaticDate()');
  1212.  
  1213.             // Replace Now() with StaticNow()
  1214.             strExpr = strExpr.replace(/now\(\)/gi, 'StaticNow()');
  1215.  
  1216.             strExpr = strExpr.replace(/\[page\]/gi, 'Page()');
  1217.             strExpr = strExpr.replace(/\[pages\]/gi, 'Pages()');
  1218.  
  1219.             strExpr = strExpr.replace(/is\s+null/gi, '= \"\"');
  1220.             strExpr = strExpr.replace(/is\s+not\s+null/gi, '<> \"\"');
  1221.  
  1222.             strExpr = FixNzFunction(strExpr);
  1223.  
  1224.             //
  1225.             // Replace references to other expressions with the dynamically generated expression gExpr_*
  1226.             //
  1227.  
  1228.             if (objElem.selectSingleNode("@id") != null)
  1229.                 objNodes = objElem.selectNodes("/RPTML/REPORT[1]/SECTION/REPORT-ITEM[@id != '' and @id != '" + objElem.selectSingleNode("@id").text + "']");
  1230.             else
  1231.                 objNodes = objElem.selectNodes("/RPTML/REPORT[1]/SECTION/REPORT-ITEM[@id != '']");
  1232.  
  1233.             for (var iNode = 0; iNode < objNodes.length; iNode++)
  1234.                 {
  1235.                 var objNode = objNodes.item(iNode);                    
  1236.                 var strRunningSum = GetNodeText(objNode, "RUNNING-SUM", "");
  1237.                 strType = GetNodeText(objNode, "ENCODED-CONTROL-SOURCE/@type", "");
  1238.  
  1239.                 if (strType == "expression" || strRunningSum == "over group" || strRunningSum == "over all")
  1240.                     {
  1241.                     var strNodeID = objNode.selectSingleNode("@id").text;
  1242.                     var strSource = "";
  1243.                     if (fReplaceWithExpr)
  1244.                         strSource = ((strRunningSum == "over group" || strRunningSum == "over all") ? "gRunningSum_" : "gExpr_") + GenerateVBName(strNodeID);
  1245.                     else if (strType == "expression")
  1246.                         strSource = objNode.selectSingleNode("ENCODED-CONTROL-SOURCE").text;
  1247.  
  1248.                     if (strSource != "")
  1249.                         strExpr = strExpr.replace(new RegExp("\\[" + strNodeID + "\\]", "gi"), "(" + strSource + ")");
  1250.                     }
  1251.                 }
  1252.  
  1253.             if (!FIsValidExpression(strExpr))
  1254.                 return "\"\"";
  1255.  
  1256.             //
  1257.             // Replace all references to fields with GetValue statement
  1258.             //
  1259.  
  1260.             strExpr = FixGetValue(strExpr);                
  1261.  
  1262.             //
  1263.             // Fix up all instances of total functions (sum, count, avg, min, max)
  1264.             //
  1265.             for (var iTotal = 0; iTotal < rgTotal.length; iTotal++)
  1266.                 {
  1267.                 strExpr = FixAggregate(rgTotal[iTotal], strExpr);                    
  1268.                 }                
  1269.  
  1270.             strExpr = FixFormat(strExpr);
  1271.  
  1272.             return strExpr;
  1273.             }
  1274.  
  1275.         function FixFormat(strExpr)
  1276.             {
  1277.             var strFunctionName = "Format";
  1278.             if (strExpr == null || strExpr.length == 0 || strExpr.match(new RegExp(strFunctionName + "\\(", "i")) == null)
  1279.                 return strExpr;
  1280.  
  1281.             var strInFunction = "";
  1282.             var strAfterFunction = "";
  1283.             var strBeforeFunction = strExpr.replace(new RegExp("\^(.*)" + strFunctionName + ".*$", "i"), "$1" + strFunctionName + "\(");
  1284.             var strTemp = strExpr.replace(new RegExp("\^.*" + strFunctionName + "\\(", "i"), "");
  1285.             // find matching parens
  1286.             var len = strTemp.length
  1287.             var count = 1;
  1288.             for(var i=0; i<len; i++)
  1289.                 {
  1290.                 if (count > 0) //before the matching paren
  1291.                     {
  1292.                     if (strTemp.charAt(i) == '(')
  1293.                         count++;
  1294.                     else if (strTemp.charAt(i) == ')')
  1295.                         count--;
  1296.                     if (count > 0)
  1297.                         strInFunction += strTemp.charAt(i);
  1298.                     }
  1299.                 else //after the matching paren
  1300.                     {
  1301.                     strAfterFunction += strTemp.charAt(i);
  1302.                     }
  1303.                 }
  1304.  
  1305.             var nType = GetDataType(strInFunction);
  1306.             
  1307.             return strBeforeFunction + strInFunction + ", \"\", \"\", " + nType + ")" + strAfterFunction;
  1308.             }
  1309.  
  1310.  
  1311.         function FixAggregate(strFunctionName, strExpr)
  1312.             {
  1313.             if (strExpr == null || strExpr.length == 0 || strExpr.match(new RegExp(strFunctionName + "\\(", "i")) == null)
  1314.                 return strExpr;
  1315.  
  1316.             var strInFunction = "";
  1317.             var strAfterFunction = "";
  1318.             // var strBeforeFunction = strExpr.replace(new RegExp("\^(.*)" + strFunctionName + ".*$", "i"), "$1" + strFunctionName + "\(");
  1319.             var strBeforeFunction = strExpr.replace(new RegExp("\^(.*)" + strFunctionName + ".*$", "i"), "$1");
  1320.             var strTemp = strExpr.replace(new RegExp("\^.*" + strFunctionName + "\\(", "i"), "");
  1321.             // find matching parens
  1322.             var len = strTemp.length
  1323.             var count = 1;
  1324.             for(var i=0; i<len; i++)
  1325.                 {
  1326.                 if (count > 0) //before the matching paren
  1327.                     {
  1328.                     if (strTemp.charAt(i) == '(')
  1329.                         count++;
  1330.                     else if (strTemp.charAt(i) == ')')
  1331.                         count--;
  1332.                     if (count > 0)
  1333.                         strInFunction += strTemp.charAt(i);
  1334.                     }
  1335.                 else //after the matching paren
  1336.                     {
  1337.                     strAfterFunction += strTemp.charAt(i);
  1338.                     }
  1339.                 }
  1340.  
  1341.             // return strBeforeFunction + "\"" + DoubleQuotes(strInFunction) + "\")" + strAfterFunction;
  1342.             return FixAggregate(strFunctionName, strBeforeFunction) + strFunctionName + "(\"" + 
  1343.                     DoubleQuotes(strInFunction) + "\")" + 
  1344.                     FixAggregate(strFunctionName, strAfterFunction);
  1345.             }
  1346.  
  1347.         function FixGetValue(strExpr)
  1348.             {
  1349.             if (strExpr == null || strExpr.length == 0 || strExpr.match(/^[^\[]*\[[^\]]*\]/) == null)
  1350.                 return strExpr;
  1351.                         
  1352.             var strBeforeFunction = strExpr.replace(/^([^\[]*)\[.*$/, "$1");
  1353.             var strInFunction = FixupFieldNames(strExpr.replace(/^[^\[]*\[([^\]]*)\].*$/, "$1"), false, false);
  1354.             var strAfterFunction = strExpr.replace(/^[^\[]*\[[^\]]*\](.*)$/, "$1");
  1355.             var nDataType = GetDataType(strInFunction);
  1356.             strInFunction = FixupFieldNames(strInFunction, true, false);
  1357.  
  1358.             return strBeforeFunction + "GetValue(\"" + strInFunction + "\", " + nDataType + ")" + FixGetValue(strAfterFunction);
  1359.             }
  1360.  
  1361.         function FixNzFunction(strExpr)
  1362.             {
  1363.             if (strExpr == null || strExpr.length == 0 || strExpr.match(/nz\(/gi) == null)
  1364.                 return strExpr;
  1365.  
  1366.             var strInFunction = "";
  1367.             var strAfterFunction = "";
  1368.             var strBeforeFunction = strExpr.replace(new RegExp("\^(.*)nz.*$", "i"), "$1Nz\(");
  1369.             var strTemp = strExpr.replace(new RegExp("\^.*nz\\(", "i"), "");
  1370.             // find matching parens
  1371.             var len = strTemp.length
  1372.             var count = 1;
  1373.             for(var i=0; i<len; i++)
  1374.                 {
  1375.                 if (count > 0) //before the matching paren
  1376.                     {
  1377.                     if (strTemp.charAt(i) == '(')
  1378.                         count++;
  1379.                     else if (strTemp.charAt(i) == ')')
  1380.                         count--;
  1381.                     if (count > 0)
  1382.                         strInFunction += strTemp.charAt(i);
  1383.                     }
  1384.                 else //after the matching paren
  1385.                     {
  1386.                     strAfterFunction += strTemp.charAt(i);
  1387.                     }
  1388.                 }
  1389.  
  1390.             if (strInFunction.match(/,/) == null)
  1391.                 return strBeforeFunction + strInFunction + ",\"\")" + strAfterFunction;
  1392.             else 
  1393.                 return strExpr;
  1394.             }
  1395.  
  1396.         var arrNames = new Array();
  1397.         function GenerateVBName(strDesiredName)
  1398.             {            
  1399.             for (var i=0; i<arrNames.length; i++)
  1400.                 {
  1401.                 if (arrNames[i] == strDesiredName)
  1402.                     return i;
  1403.                 }
  1404.  
  1405.             arrNames = arrNames.concat(strDesiredName);
  1406.             return i;
  1407.             }
  1408.  
  1409.         function ConvertControlSource(nodelist)
  1410.             {
  1411.             return ConvertControlSourceFromNode(nodelist.item(0), false);
  1412.             }
  1413.             
  1414.         function ConvertControlSourceFromNode(objElem, fGrouping)
  1415.             {
  1416.             var strType = GetNodeText(objElem, "@type", "");
  1417.             var strRunningSum = GetNodeText(objElem, "../RUNNING-SUM", "");
  1418.  
  1419.             if (fGrouping && strType == "expression")
  1420.                 return "fx:GroupExpr_" + GenerateVBName(GetNodeText(objElem, "../@id", "")) + "(.)";
  1421.             else if (strType == "expression" || strRunningSum == "over group" || strRunningSum == "over all")
  1422.                 return "fx:ExprFromXSL_" + GenerateVBName(GetNodeText(objElem, "../@id", "")) + "()";
  1423.             else if (fGrouping)
  1424.                 return objElem.text;
  1425.             else
  1426.                 return AddFormattingFromNode("fx:FormatFromXSL", objElem.text, objElem);
  1427.             }
  1428.  
  1429.         function AddFormatting(strFunctionName, strRef, nodelist)
  1430.             {
  1431.             return AddFormattingFromNode(strFunctionName, strRef, nodelist.item(0));
  1432.             }
  1433.             
  1434.         function AddFormattingFromNode(strFunctionName, strRef, objElem)
  1435.             {
  1436.             if (strRef == "\"\"")
  1437.                 return strRef;
  1438.  
  1439.             var strFormat = GetNodeText(objElem, "../FORMAT", "");
  1440.             var strQuote;
  1441.             var strFormat;
  1442.             var strNewRef;
  1443.             var strDecimalPlaces = "";
  1444.             var strLcid = "";
  1445.             var nType = GetDataType(GetNodeText(objElem, "../CONTROL-SOURCE", ""));
  1446.             
  1447.             if (strFunctionName == "fx:FormatFromXSL")
  1448.                 {
  1449.                 strQuote = "'";
  1450.                 strFormat = DoubleSingleQuotes(strFormat);
  1451.                 strNewRef = strQuote + FixupFieldNames(objElem.text, true, false) + strQuote;
  1452.                 }
  1453.             else
  1454.                 {
  1455.                 strQuote = "\"";
  1456.                 strFormat = DoubleQuotes(strFormat);
  1457.                 strNewRef = strRef;
  1458.                 }    
  1459.  
  1460.             switch (strFormat)
  1461.                 {        
  1462.                 case "General Number":
  1463.                 case "General Date":
  1464.                 case "Long Date":
  1465.                 case "Long Time":
  1466.                 case "Medium Time":
  1467.                 case "Short Time":
  1468.                 case "True/False":
  1469.                 case "Yes/No":
  1470.                 case "On/Off":
  1471.                 case "Medium Date":
  1472.                 case "Short Date":
  1473.                     break;
  1474.                 case "Currency":        
  1475.                     strDecimalPlaces = GetNodeText(objElem, "../DECIMAL-PLACES", "2");
  1476.                     strLcid = GetNodeText(objElem, "../FORMAT-LCID", "");            
  1477.                     break;
  1478.                 case "Euro":
  1479.                     strDecimalPlaces = GetNodeText(objElem, "../DECIMAL-PLACES", "2");
  1480.                     strLcid = GetNodeText(objElem, "../FORMAT-LCID", "");            
  1481.                     break;
  1482.                 case "Fixed":
  1483.                 case "Standard":
  1484.                 case "Percent":
  1485.                 case "Scientific":
  1486.                     strDecimalPlaces = GetNodeText(objElem, "../DECIMAL-PLACES", "2");
  1487.                     break;
  1488.                 default :
  1489.                     switch (nType)
  1490.                         {
  1491.                         case 6:          // adCurrency
  1492.                             strDecimalPlaces = GetNodeText(objElem, "../DECIMAL-PLACES", "2");
  1493.                             strLcid = GetNodeText(objElem, "../FORMAT-LCID", "");            
  1494.                             break;
  1495.                         case 7:        // adDate
  1496.                         case 133:    // adDBDate
  1497.                         case 134:     // adDBTime
  1498.                         case 135:    // adDBTimeStamp
  1499.                             break;
  1500.                         default :
  1501.                             // Only skip the formatting if the format property was empty and
  1502.                             // the data type was not currency or date.
  1503.                             if (strFormat == "")
  1504.                                 {
  1505.                                 // If we are in the report or page header or footer,
  1506.                                 // we need to tack on $GlobalGroup/
  1507.                                 var strSectionType = GetNodeText(objElem, "../../@type", "");
  1508.                                 if (strFunctionName == "fx:FormatFromXSL")
  1509.                                     {
  1510.                                     switch (strSectionType)
  1511.                                         {
  1512.                                         case "report_header":
  1513.                                         case "page_header":
  1514.                                         case "report_footer":
  1515.                                         case "page_footer":
  1516.                                             return "$GlobalGroup/" + strRef;
  1517.                                         }
  1518.                                     }
  1519.                                 return strRef;
  1520.                                 }
  1521.                             break;
  1522.                         }
  1523.                     break;
  1524.                 }
  1525.  
  1526.             return strFunctionName + "(" + strNewRef + ", " 
  1527.                                     + strQuote + strFormat + strQuote + ", " 
  1528.                                     + strQuote + strDecimalPlaces + strQuote + ", " 
  1529.                                     + strQuote + strLcid + strQuote + ", " 
  1530.                                     + nType + ")";
  1531.             }
  1532.  
  1533.         function GetDataType(strFieldName)
  1534.             {
  1535.             var strRecordSource = null;
  1536.             var objRowSource = null;
  1537.             var datatype = null;
  1538.  
  1539.             strRecordSource = GetNodeText(gRPTML, "/RPTML/REPORT/ENCODED-RECORD-SOURCE", "");
  1540.             strRecordSource = strRecordSource.replace(/^[ ]*(.+[^ ])[ ]*$/, '$1');        // remove spaces from beginning and end
  1541.             objRowSource = gRPTML.selectSingleNode("/RPTML/REPORT[1]/DATA-MODEL/ROW-SOURCE[@id='" + strRecordSource + "']");
  1542.  
  1543.             if (objRowSource == null && !CaseInsensitiveCompare("SELECT", strRecordSource.substr(0, 6)))
  1544.                 {
  1545.                 // If the RECORD-SOURCE is of the form dbo.Table we need to remove the dbo and try again.
  1546.                 var arrParts = strRecordSource.split(".");            
  1547.                 if (arrParts.length == 2)                // If RECORD-SOURCE was split into 2 parts
  1548.                     {
  1549.                     strRecordSource = arrParts[1];    // Take the second part.  
  1550.                     objRowSource = gRPTML.selectSingleNode("/RPTML/REPORT[1]/DATA-MODEL/ROW-SOURCE[@id='" + strRecordSource + "']");
  1551.                     }
  1552.                 }
  1553.  
  1554.             if (objRowSource != null)
  1555.                 datatype = objRowSource.selectSingleNode("FIELD[@id='" + FixupFieldNames(strFieldName, false, true) + "']/@datatype");
  1556.  
  1557.             if (datatype != null)
  1558.                 return Number(datatype.text);
  1559.  
  1560.             return 8; // string type
  1561.             }
  1562.  
  1563.         function IsNumberType(nDataType, fIsDateANumber, fDefault)
  1564.             {
  1565.             switch (nDataType)
  1566.                 {
  1567.                 case 16:    // adTinyInt
  1568.                 case 2:        // adSmallInt
  1569.                 case 3:        // adInteger
  1570.                 case 20:    // adBigInt
  1571.                 case 17:    // adUnsignedTinyInt
  1572.                 case 18:    // adUnsignedSmallInt
  1573.                 case 19:    // adUnsignedInt
  1574.                 case 21:    // adUnsignedBigInt
  1575.                 case 4:        // adSingle
  1576.                 case 5:        // adDouble
  1577.                 case 6:        // adCurrency
  1578.                 case 14:    // adDecimal
  1579.                 case 131:    // adNumeric
  1580.                 case 139:    // adVarNumeric
  1581.                 case 11:    // adBoolean
  1582.                     return true;
  1583.                 case 7:        // adDate
  1584.                 case 133:    // adDBDate
  1585.                 case 134:    // adDBTime
  1586.                 case 135:    // adDBTimeStamp
  1587.                     return fIsDateANumber;
  1588.                 case 8:        // adBSTR
  1589.                 case 120:    // adChar
  1590.                 case 200:    // adVarChar
  1591.                 case 201:    // adLongVarChar
  1592.                 case 130:    // adWChar:
  1593.                 case 202:    // adVarWChar
  1594.                 case 203:    // adLongVarWChar
  1595.                     return false;
  1596.                 default:
  1597.                     return fDefault;
  1598.                 }
  1599.             }
  1600.  
  1601.         var rgTextAttr = new Array("COLOR", "BACKGROUND-COLOR", "BORDER-WIDTH", "BORDER-COLOR", "TEXT-ALIGN", "WRITING-MODE", "VISIBILITY",
  1602.                                    "FONT-WEIGHT", "FONT-SIZE", "FONT-FAMILY", "FONT-STYLE", "LEFT", "TOP", "WIDTH", "HEIGHT", "TEXT-DECORATION",
  1603.                                    "PADDING-TOP", "PADDING-BOTTOM", "PADDING-RIGHT", "PADDING-LEFT");
  1604.                                    
  1605.         function GetTextStyle(nodelist, fIsSection)
  1606.             {
  1607.             var objSource;
  1608.             var objClass;
  1609.             var objWidth;
  1610.             var objElem = nodelist.item(0);
  1611.             var strStyle = GetBorderStyle(objElem);
  1612.             objSource = SelectSingleNodeNoThrow(objElem,"CONTROL-SOURCE");
  1613.             objClass = SelectSingleNodeNoThrow(objElem, "CLASS");
  1614.             objWidth = SelectSingleNodeNoThrow(objElem,"WIDTH");
  1615.  
  1616.             var objTextAlign = null;
  1617.             if (objClass != null)
  1618.                 objTextAlign = objElem.selectSingleNode("/RPTML/REPORT[1]/STYLE[@id='" + objClass.text + "']/TEXT-ALIGN");
  1619.             if (objSource != null && (objTextAlign == null ||objTextAlign.text == "general") && IsNumberType(GetDataType(objSource.text), true, false))
  1620.                 strStyle = strStyle + "TEXT-ALIGN: right; ";
  1621.  
  1622.             if (objWidth == null && fIsSection)
  1623.                 {
  1624.                 var strWidth = GetNodeText(objElem, "/RPTML/REPORT[1]/WIDTH", "");
  1625.                 if (strWidth != "")
  1626.                     strStyle = strStyle + "WIDTH: " + strWidth + "; ";
  1627.                 }
  1628.                 
  1629.             return strStyle + GetItemStyle(objElem, rgTextAttr);
  1630.             }
  1631.  
  1632.         function GetBorderStyle(objElem)
  1633.             {
  1634.             var objBS;
  1635.             objBS = SelectSingleNodeNoThrow(objElem,"BORDER-STYLE");
  1636.  
  1637.             if (objBS != null)
  1638.                 {
  1639.                 if (objBS.text == "solid" || objBS.text == "double-solid")
  1640.                     return "BORDER-STYLE: solid; ";
  1641.                 if (objBS.text == "dashed" || objBS.text == "short-dashes" || objBS.text == "dash-dot")
  1642.                     return "BORDER-STYLE: dashed; ";
  1643.                 if (objBS.text == "dotted" || objBS.text == "sparse-dots" || objBS.text == "dash-dot-dot")
  1644.                     return "BORDER-STYLE: dotted; ";
  1645.                 return "BORDER-STYLE: " + objBS.text + "; ";
  1646.                 }
  1647.             return "";
  1648.             }
  1649.  
  1650.         var rgCheckboxStyle = new Array("LEFT", "TOP", "HEIGHT", "VISIBILITY");
  1651.  
  1652.         function GetCheckboxStyle(nodelist)
  1653.             {
  1654.             return GetItemStyle(nodelist.item(0), rgCheckboxStyle);
  1655.             }
  1656.  
  1657.         var rgHyperlinkAttr = new Array("BORDER-WIDTH", "BORDER-COLOR", "BORDER-STYLE", "TEXT-ALIGN",
  1658.                                         "FONT-WEIGHT", "FONT-SIZE", "FONT-FAMILY", "FONT-STYLE", "VISIBILITY", "LEFT", "TOP", "WIDTH", "HEIGHT");
  1659.  
  1660.         function GetHyperlinkStyle(nodelist)
  1661.             {
  1662.             return GetItemStyle(nodelist.item(0), rgHyperlinkAttr);
  1663.             }
  1664.  
  1665.         var rgLineAttr = new Array("COLOR", "BACKGROUND-COLOR", "BORDER-WIDTH", "BORDER-COLOR", "BORDER-STYLE", "VISIBILITY",
  1666.                                    "LEFT", "TOP");
  1667.  
  1668.         function GetLineStyle(nodelist)
  1669.             {
  1670.             var objElem = nodelist.item(0);
  1671.             var strStyle = GetItemStyle(objElem, rgLineAttr);
  1672.  
  1673.             var objBorder = GetStyleNode(objElem, "BORDER-WIDTH");
  1674.             if (objBorder != null)
  1675.                 {
  1676.                 var strWidth = objElem.selectSingleNode("WIDTH").text;
  1677.                 if (strWidth == "0in")
  1678.                     strWidth = objBorder.text;
  1679.  
  1680.                 var strHeight = objElem.selectSingleNode("HEIGHT").text;
  1681.                 if (strHeight == "0in")
  1682.                     strHeight = objBorder.text;
  1683.  
  1684.                 if (strStyle.length > 0)
  1685.                     strStyle = strStyle + "; ";
  1686.                 strStyle = strStyle + "WIDTH: " + strWidth;
  1687.                 strStyle = strStyle + "; HEIGHT: " + strHeight;
  1688.                 }
  1689.  
  1690.             return strStyle;
  1691.             }
  1692.  
  1693.         var rgRectAttr = new Array("COLOR", "BACKGROUND-COLOR", "BORDER-WIDTH", "BORDER-COLOR", "BORDER-STYLE", "VISIBILITY",
  1694.                                    "LEFT", "TOP", "WIDTH", "HEIGHT");
  1695.  
  1696.         function GetRectangleStyle(nodelist)
  1697.             {
  1698.             return GetItemStyle(nodelist.item(0), rgRectAttr);
  1699.             }
  1700.  
  1701.         var rgImageAttr = new Array("BORDER-WIDTH", "BORDER-COLOR", "BORDER-STYLE", "VISIBILITY",
  1702.                                     "LEFT", "TOP", "WIDTH", "HEIGHT");
  1703.  
  1704.         function GetImageStyle(nodelist)
  1705.             {
  1706.             var objElem = nodelist.item(0);
  1707.             var strStyle = GetItemStyle(objElem, rgImageAttr);
  1708.  
  1709.             if (strStyle.length > 0)
  1710.                 strStyle = strStyle + "; ";
  1711.             strStyle = strStyle + "BACKGROUND-COLOR: silver";
  1712.  
  1713.             return strStyle;
  1714.             }
  1715.  
  1716.         var rgBodyAttr = new Array("BACKGROUND-POSITION", "BACKGROUND-REPEAT");
  1717.  
  1718.         function GetBodyStyle(nodelist)
  1719.             {
  1720.             var objElem = nodelist.item(0);
  1721.             var strStyle = "";
  1722.             var objImage = objElem.selectSingleNode("/RPTML/REPORT[1]/BACKGROUND-IMAGE")
  1723.             if (objImage != null) 
  1724.                 {
  1725.                 strStyle = "BACKGROUND-IMAGE:url('" + objImage.text + "'); ";
  1726.                 strStyle += GetItemStyle(objElem.selectSingleNode("/RPTML/REPORT[1]"), rgBodyAttr);
  1727.                 }        
  1728.                     
  1729.             return strStyle;
  1730.             }    
  1731.  
  1732.         function GetItemStyle(objElem, rgAttr)
  1733.             {
  1734.             var cStyles = 0;
  1735.             var strStyle = "";
  1736.             for (var iAttr in rgAttr)
  1737.                 if (SelectSingleNodeNoThrow(objElem, rgAttr[iAttr]) != null)
  1738.                     {
  1739.                     if (cStyles > 0)
  1740.                         strStyle = strStyle + "; ";
  1741.                     strStyle = strStyle + rgAttr[iAttr] + ": " + objElem.selectSingleNode(rgAttr[iAttr]).text;
  1742.                     cStyles++;
  1743.                     }
  1744.  
  1745.             return strStyle;
  1746.             }
  1747.  
  1748.         function GetStyleNode(objElem, strName)
  1749.             {
  1750.             var objWidth = objElem.selectSingleNode(strName);
  1751.             if (objWidth == null)
  1752.                 objWidth = objElem.selectSingleNode("/RPTML/REPORT[1]/STYLE[@id='"+objElem.selectSingleNode("CLASS").text+"']/" + strName);
  1753.             return objWidth;
  1754.             }
  1755.  
  1756.         //
  1757.         // Gets the Field name from a table.field name, also makes sure field is correct case
  1758.         //
  1759.         function FixupFieldNames(strField, fConvertSpaces, fRequireDataModel)
  1760.             {
  1761.             var strFieldName = strField.replace(/.*\./, ''); //strip out table in table.field
  1762.             var objFields = gRPTML.selectNodes("/RPTML/REPORT[1]/DATA-MODEL/ROW-SOURCE/FIELD[@id]");
  1763.             var strTemp = "";
  1764.  
  1765.             for (var i = 0; i < objFields.length; i++)
  1766.                 {
  1767.                 strTemp = GetNodeText(objFields.item(i), "@id", "");
  1768.                 if (CaseInsensitiveCompare(strTemp, strFieldName) || CaseInsensitiveCompare(strTemp, strField))
  1769.                     {            
  1770.                     return (fConvertSpaces ? GetNodeText(objFields.item(i), "@encoded-id", "") : strTemp);
  1771.                     }
  1772.                 }
  1773.             return (fRequireDataModel ? "" : (fConvertSpaces ? CleanUpFieldName(strFieldName) : strFieldName));
  1774.             }    
  1775.  
  1776.         function CaseInsensitiveCompare(str1, str2)
  1777.             {
  1778.             return str1.toUpperCase() == str2.toUpperCase();
  1779.             }
  1780.  
  1781.         function CleanUpFieldName(strFieldName)
  1782.             {
  1783.             strTemp = strFieldName.replace(/ /g, '_x0020_'); // spaces in data xml are _x0020_
  1784.             var lFirstChar = strTemp.charCodeAt(0) - 48;  
  1785.             if (lFirstChar > -1 && lFirstChar < 10)
  1786.                 {
  1787.                 strTemp = "_x003" + lFirstChar + "_" + strTemp.substr(1); // replace initial #
  1788.                 }
  1789.             return strTemp;
  1790.             }
  1791.  
  1792.         function DoubleQuotes(strExpr)
  1793.             {
  1794.             return strExpr.replace(/\"/g, "\"\"");
  1795.             }
  1796.             
  1797.         function DoubleSingleQuotes(strExpr)
  1798.             {
  1799.             return strExpr.replace(/\'/g, "''");
  1800.             }
  1801.             
  1802.         function GetCheckboxCondition(nodelist)
  1803.             {
  1804.             var objElem = nodelist.item(0);
  1805.             var objSource = objElem.selectSingleNode("ENCODED-CONTROL-SOURCE");
  1806.             if (objSource != null)
  1807.                 {
  1808.                 if (GetNodeText(objSource, "@type", "") == "expression")
  1809.                     {
  1810.                     return ConvertControlSourceFromNode(objSource, false);
  1811.                     }
  1812.                 else
  1813.                     {
  1814.                     var strSource = FixupFieldNames(objSource.text, true, false);
  1815.  
  1816.                     // Always return a boolean
  1817.                     return "fx:GetValue('" + strSource + "', 11)";                
  1818.                     }
  1819.                 }
  1820.             return '0';
  1821.             }
  1822.     
  1823.         function GetNodeTextFromNodeList(nodelist, strPath, strDefault)
  1824.             {            
  1825.             return GetNodeText(nodelist.item(0), strPath, strDefault);
  1826.             }
  1827.  
  1828.         function GetNodeText(objNode, strPath, strDefault)
  1829.             {
  1830.             var objResult;
  1831.             if (objNode != null)
  1832.                 objResult = objNode.selectSingleNode(strPath);
  1833.             return (objResult != null ? objResult.text : strDefault);
  1834.             }    
  1835.  
  1836.         function FixInnerQuotes(strExpr)
  1837.             {
  1838.             var fNeedMatchSingleQuote = false;
  1839.             var fNeedMatchDoubleQuote = false;
  1840.             var fIsSingleQuote = false;
  1841.             var fIsDoubleQuote = false;
  1842.             var len = strExpr.length;
  1843.             var strTemp = "";
  1844.             for(var i=0; i<len; i++)
  1845.                 {
  1846.                 fIsDoubleQuote = strExpr.charAt(i) == '"';
  1847.                 fIsSingleQuote = strExpr.charAt(i) == "'";
  1848.                 if (fIsSingleQuote || fIsDoubleQuote)
  1849.                     {
  1850.                     if (fNeedMatchSingleQuote)
  1851.                         {
  1852.                         if (fIsDoubleQuote)
  1853.                             {
  1854.                             strTemp += "\"\"";
  1855.                             }
  1856.                         else
  1857.                             {
  1858.                             strTemp += "\"";
  1859.                             fNeedMatchSingleQuote = false;
  1860.                             }
  1861.                         }
  1862.                     else if (fNeedMatchDoubleQuote)
  1863.                         {
  1864.                         if (fIsDoubleQuote)
  1865.                             {
  1866.                             strTemp += "\"";
  1867.                             fNeedMatchDoubleQuote = false;
  1868.                             }
  1869.                         else
  1870.                             {
  1871.                             strTemp += "'";
  1872.                             }
  1873.                         }
  1874.                     else // found a beginning qoute
  1875.                         {
  1876.                         if (fIsDoubleQuote)
  1877.                             fNeedMatchDoubleQuote = true;
  1878.                         else
  1879.                             fNeedMatchSingleQuote = true;
  1880.                         strTemp += "\"";
  1881.                         }
  1882.                     }
  1883.                 else
  1884.                     {
  1885.                     strTemp += strExpr.charAt(i);
  1886.                     }
  1887.                 }
  1888.                 return strTemp;
  1889.             }
  1890.  
  1891.         function FIsValidExpression(strSource)
  1892.             {
  1893.             if ((strSource.match(/\!/i) != null) || 
  1894.                 (strSource.match(/\[Forms\]\!/i) != null) || 
  1895.                 (strSource.match(/Forms\!/i) != null) ||
  1896.                 (strSource.match(/Forms\([^\!]*\!/i) != null) ||
  1897.                 (strSource.match(/\[Reports\]\!/i) != null)  || 
  1898.                 (strSource.match(/Reports\!/i) != null) ||
  1899.                 (strSource.match(/Reports\([^\!]*\!/i) != null) ||
  1900.                 (strSource.match(/\[Form\]\!/i) != null) || 
  1901.                 (strSource.match(/Form\!/i) != null) ||
  1902.                 (strSource.match(/Form\([^\!]*\!/i) != null) ||
  1903.                 (strSource.match(/\[Report\]\!/i) != null)  || 
  1904.                 (strSource.match(/Report\!/i) != null) ||
  1905.                 (strSource.match(/Report\([^\!]*\!/i) != null))
  1906.                 return false;
  1907.             else
  1908.                 return true;
  1909.             }
  1910.  
  1911.         function SmartTagHTML(fBeginTag)
  1912.             {
  1913.             var strHTMLtag = "";
  1914.  
  1915.             if (fBeginTag)
  1916.                 strHTMLtag += "<html";
  1917.             else
  1918.                 strHTMLtag += ">";
  1919.  
  1920.             return strHTMLtag;
  1921.             }
  1922.  
  1923.         function NonSmartTagHTML(fOpenTag)
  1924.             {
  1925.             var strHTMLtag = "";
  1926.  
  1927.             if (fOpenTag)
  1928.                 strHTMLtag += "<html>";
  1929.             else
  1930.                 strHTMLtag += "</html>";
  1931.  
  1932.             return strHTMLtag;
  1933.             }
  1934.             
  1935.         function GetSmartTag(nodelist, fOpenTag)
  1936.             {
  1937.             var objElem = nodelist.item(0);
  1938.             var strTag = "<";
  1939.             var objTagPrefix = objElem.selectSingleNode("SMART-TAG-PREFIX");
  1940.             var objTagName = objElem.selectSingleNode("SMART-TAG-NAME");
  1941.             var strTagPrefix = objTagPrefix.text;
  1942.             var strTagName = objTagName.text;
  1943.  
  1944.             if (!fOpenTag)
  1945.                 strTag += "/";
  1946.  
  1947.             strTag += strTagPrefix;
  1948.             strTag += ":";
  1949.             strTag += strTagName;
  1950.             strTag += ">";
  1951.  
  1952.             return strTag;
  1953.             }
  1954.  
  1955.         var iCtrlID = 1;
  1956.         function GetNextCtrlID()
  1957.             {
  1958.             return "CTRL" + (iCtrlID++);
  1959.             }
  1960.  
  1961.         function StylesheetStart()
  1962.             {
  1963.             return "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:msxsl='urn:schemas-microsoft-com:xslt' xmlns:fx='#fx-functions' exclude-result-prefixes='msxsl fx'>\n";
  1964.             }
  1965.  
  1966.         function StylesheetEnd()
  1967.             {
  1968.             return "\n</xsl:stylesheet>";
  1969.             }
  1970.             
  1971.         function SelectSingleNodeNoThrow(objElm, strXPath)
  1972.         {
  1973.             var objRet;
  1974.             try
  1975.             {
  1976.                 objRet = objElm.selectSingleNode(strXPath);
  1977.             }
  1978.             catch(e)
  1979.             {
  1980.             }
  1981.             return objRet;
  1982.         }
  1983.             
  1984.     ]]></msxsl:script>
  1985.  
  1986. </xsl:stylesheet>
  1987.  
  1988.