Search code examples
xslt

Recursive Template Generating Extra Stuff


I am working with Xml that that has multiple levels where I am attempting to display as nested html tables. The Xml may contain one or more levels of information. The current state is the information from the Xml is shown, but has extra empty tables.

Below is the Xml and template I am using. How should I correct the problem?

<?xml version="1.0" encoding="UTF-8"?>
<ErrorRecord>
   <Exception>
      <ErrorRecord>Exception calling "Fill" with "2" argument(s): "Divide by zero error encountered."</ErrorRecord>
      <WasThrownFromThrowStatement>True</WasThrownFromThrowStatement>
      <TargetSite>Void CheckActionPreference(System.Management.Automation.Language.FunctionContext, System.Exception)</TargetSite>
      <Message>Exception calling "Fill" with "2" argument(s): "Divide by zero error encountered."</Message>
      <Data>System.Collections.ListDictionaryInternal</Data>
      <InnerException>
         <Error>
            <Source>Core .Net SqlClient Data Provider</Source>
            <Number>8134</Number>
            <State>1</State>
            <Class>16</Class>
            <Server>.</Server>
            <Message>Divide by zero error encountered.</Message>
            <Procedure></Procedure>
            <LineNumber>1</LineNumber>
         </Error>
         <ClientConnectionId>cdfed373-14fb-4dd7-bebf-7158695cb2c7</ClientConnectionId>
         <Class>16</Class>
         <LineNumber>1</LineNumber>
         <Number>8134</Number>
         <Procedure></Procedure>
         <Server>.</Server>
         <State>1</State>
         <Source>Core .Net SqlClient Data Provider</Source>
         <IsTransient>False</IsTransient>
         <SqlState></SqlState>
         <BatchCommand></BatchCommand>
         <ErrorCode>-2146232060</ErrorCode>
         <TargetSite>Void OnError(System.Data.SqlClient.SqlException, Boolean, System.Action`1[System.Action])</TargetSite>
         <Message>Divide by zero error encountered.</Message>
         <Data>System.Collections.ListDictionaryInternal</Data>
         <InnerException></InnerException>
         <HelpLink></HelpLink>
         <HResult>-2146232060</HResult>
         <StackTrace>   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean&amp; dataReady)
   at System.Data.SqlClient.SqlDataReader.TryHasMoreRows(Boolean&amp; moreRows)
   at System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean&amp; more)
   at System.Data.SqlClient.SqlDataReader.Read()
   at System.Data.Common.DataAdapter.FillLoadDataRow(SchemaMapping mapping)
   at System.Data.Common.DataAdapter.FillFromReader(DataSet dataset, DataTable datatable, String srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn parentChapterColumn, Object parentChapterValue)
   at System.Data.Common.DataAdapter.Fill(DataSet dataSet, String srcTable, IDataReader dataReader, Int32 startRecord, Int32 maxRecords)
   at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
   at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
   at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, String srcTable)
   at CallSite.Target(Closure, CallSite, Object, Object, Object)</StackTrace>
      </InnerException>
      <HelpLink></HelpLink>
      <Source>System.Management.Automation</Source>
      <HResult>-2146233087</HResult>
      <StackTrace>   at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)</StackTrace>
   </Exception>
</ErrorRecord>
<xsl:template match = "ErrorRecord">
    <xsl:call-template name="ErrorTable">
        <xsl:with-param name="n" select="." />
    </xsl:call-template>
</xsl:template>

<xsl:template name="ErrorTable">
    <xsl:param name="n" />
    <xsl:for-each select="$n/*">
        <table class="ErrorDetailTable">
            <tr>
                <th class="Property">&#32;</th>
                <th class="Value">&#32;</th>
            </tr>

            <xsl:for-each select="*">
                <xsl:choose>
                    <xsl:when test="position() mod 2 = 0">
                        <tr class="tr-even">
                            <xsl:call-template name="ErrorCells"/>
                        </tr>
                    </xsl:when>
                    <xsl:otherwise>
                        <tr class="tr-odd">
                            <xsl:call-template name="ErrorCells"/>
                        </tr>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>

            <tr><td colspan="2">&#32;</td></tr>
        </table>
    </xsl:for-each>
</xsl:template>

<xsl:template name="ErrorCells">
    <td class="Property"><xsl:value-of select ="local-name(.)"/></td>
    <td class="Value">
        <xsl:choose>
            <xsl:when test="count(./*) &gt; 0">
                <xsl:call-template name="ErrorTable">
                    <xsl:with-param name="n" select=".." />
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="replace_sab">
                    <xsl:with-param name="s" select="." />
                    <xsl:with-param name="a" select="'&#xA;'" />
                    <xsl:with-param name="b"><br /></xsl:with-param>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </td>
</xsl:template>

<xsl:template name="replace_sab">
    <!-- with string s, replace substring a by string b -->
    <!-- s, a and b are parameters determined upon calling  -->
    <xsl:param name="s" />
    <xsl:param name="a" />
    <xsl:param name="b" />
    <xsl:choose>
        <xsl:when test="contains($s,$a)">
            <xsl:value-of select="substring-before($s,$a)" />
            <xsl:copy-of select="$b" />
            <xsl:call-template name="replace_sab">
                <xsl:with-param name="s" select="substring-after($s,$a)" />
                <xsl:with-param name="a" select="$a" />
                <xsl:with-param name="b" select="$b" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$s" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Solution

  • I was able to find the issue, which was due to the reference to the current node with the xml. Solution is as below.

    <xsl:template match = "ErrorRecord">
        <xsl:call-template name="ErrorTable">
            <xsl:with-param name="n" select="./Exception" />
        </xsl:call-template>
    </xsl:template>
    
    <xsl:template name="ErrorTable">
        <xsl:param name="n" />
        <xsl:for-each select="$n">
            <table class="ErrorDetailTable">
                <tr>
                    <th class="Property">&#32;</th>
                    <th class="Value">&#32;</th>
                </tr>
    
                <xsl:for-each select="*">
                    <xsl:choose>
                        <xsl:when test="position() mod 2 = 0">
                            <tr class="tr-even">
                                <xsl:call-template name="ErrorCells"/>
                            </tr>
                        </xsl:when>
                        <xsl:otherwise>
                            <tr class="tr-odd">
                                <xsl:call-template name="ErrorCells"/>
                            </tr>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each>
    
                <tr><td colspan="2">&#32;</td></tr>
            </table>
        </xsl:for-each>
    </xsl:template>
    
    <xsl:template name="ErrorCells">
        <td class="Property"><xsl:value-of select ="local-name(.)"/></td>
        <td class="Value">
            <xsl:choose>
                <xsl:when test="count(./*) &gt; 0">
                    <xsl:call-template name="ErrorTable">
                        <xsl:with-param name="n" select="." />
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:call-template name="replace_sab">
                        <xsl:with-param name="s" select="." />
                        <xsl:with-param name="a" select="'&#xA;'" />
                        <xsl:with-param name="b"><br /></xsl:with-param>
                    </xsl:call-template>
                </xsl:otherwise>
            </xsl:choose>
        </td>
    </xsl:template>
    
    <xsl:template name="replace_sab">
        <!-- with string s, replace substring a by string b -->
        <!-- s, a and b are parameters determined upon calling  -->
        <xsl:param name="s" />
        <xsl:param name="a" />
        <xsl:param name="b" />
        <xsl:choose>
            <xsl:when test="contains($s,$a)">
                <xsl:value-of select="substring-before($s,$a)" />
                <xsl:copy-of select="$b" />
                <xsl:call-template name="replace_sab">
                    <xsl:with-param name="s" select="substring-after($s,$a)" />
                    <xsl:with-param name="a" select="$a" />
                    <xsl:with-param name="b" select="$b" />
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$s" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>