How to set a flag / variable in xslt for re-entry (related to converting to Junit format)

I am reading an external log file via xslt and I want to find a specific line. As soon as I find it, I want to print all the lines until I press another line. I need to do this several times for a very large log file. each iteration has a unique identifier, and the log file separates the relevant information by "iteration number: X" to "iteration number X + 1" (or EOF).

Here is my xsl: (the corresponding code is in the reject tag)

<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions"> <xsl:output method="xml" indent="yes" /> <xsl:template match="/"> <testsuites> <xsl:variable name="buildName" select="//rest/*/test_name"/> <xsl:variable name="numberOfTests" select="count(//rest/*/iter_num)"/> <xsl:variable name="numberOfFailures" select="count(//rest/*/status [.= 'Fail'])" /> <xsl:variable name="numberSkipped" select="count(//rest/*/status [.!='Pass' and .!='Fail'])" /> <xsl:variable name="logfile" select="//rest/@logfile" /> <xsl:variable name="testfile" select="//rest/@testFile" /> <testsuite name="QE AUTOMATION TESTS" tests="{$numberOfTests}" time="0" failures="{$numberOfFailures}" errors="0" skipped="{$numberSkipped}"> <xsl:for-each select="//rest/*"> <xsl:variable name="testName" select="test_name"/> <xsl:variable name="executionId" select="iter_num"/> <xsl:variable name="start_time" select="fn:replace(start_time,' ','T')" /> <xsl:variable name="end_time" select="fn:replace(end_time,' ','T')"/> <xsl:variable name="test_parameters" select="test_parameters"/> <xsl:variable name="test_positive" select="test_positive"/> <xsl:variable name="time_diff" select="xs:dateTime($end_time)-xs:dateTime($start_time)"/> <xsl:variable name="duration_seconds" select="seconds-from-duration($time_diff)"/> <xsl:variable name="duration_minutes" select="minutes-from-duration($time_diff)"/> <xsl:variable name="duration_hours" select="hours-from-duration($time_diff)"/> <xsl:variable name="outcome" select="status"/> <xsl:variable name="message" select="$buildName"/> <testcase classname="qe-tests.{local-name(.)}" name="{$testName}" time="{$duration_hours*3600 + $duration_minutes*60 + $duration_seconds }"> <xsl:if test="contains($outcome, 'Fail')"> <failure> <xsl:param name="executionEnd" select="$executionId +1"/> <xsl:variable name="postIterX" select="tokenize(.,concat('Iteration number: ',$executionId,'\r?\n'),'m')[2]"/> <xsl:variable name="inIterX" select="tokenize($postIterX, concat('\r?\n.*Iteration number: ',$executionEnd,'\r?\n?'),'m')[1]"/> <xsl:value-of select="$inIterX"/> </failure> </xsl:if> </testcase> </xsl:for-each> </testsuite> </testsuites> </xsl:template> </xsl:stylesheet> 

i updated to code to use @empo solution, but there is an error when using xsl: param in this way.

the log file I have is similar to this (this is a simplified snippet) (beginning on the line “Iteration 70” and stopping on Iteration 71 ”in this example)

 2011-06-15 15:38:07,126 - networks - INFO - Compared entities are equal 2011-06-15 15:38:07,152 - rest-Main - INFO - Test status for iteration 60 Pass 2011-06-15 15:38:07,187 - rest-Main - INFO - Test name: add Network To Cluster 2011-06-15 15:38:07,192 - rest-Main - INFO - Iteration number: 70 2011-06-15 15:38:07,187 - rest-Main - INFO - Test action: addNetworkToCluster 2011-06-15 15:38:07,188 - rest-Main - INFO - Run test: yes 2011-06-15 15:38:07,188 - rest-Main - INFO - Test positive: TRUE 2011-06-15 15:38:07,152 - rest-Main - INFO - Test status for iteration 70 Fail 2011-06-15 15:38:07,192 - rest-Main - INFO - Iteration number: 71 2011-06-15 15:38:07,188 - rest-Main - INFO - Test positive: DDDDD 2011-06-15 15:38:07,188 - rest-Main - INFO - Run test: yes 2011-06-15 15:38:07,188 - rest-Main - INFO - Test positive: TRUE * EOF 

the desired xml output is as follows: (verbose output will only be shown on error)

 <?xml version="1.0" encoding="UTF-8"?> <testsuites xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <testsuite name="QE AUTOMATION TESTS" tests="2" time="0" failures="1" errors="0" skipped="0"> <testcase classname="qe-tests.Network" name="Add Network to Cluster="3"> <failure> 2011-06-15 15:38:05,674 - rest-Main - INFO - Iteration number: 70 2011-06-15 15:38:05,674 - rest-Main - INFO - Running function: networks.addNetworkToCluster 2011-06-15 15:38:05,675 - rest-Main - INFO - Running command: testStatus=addNetworkToCluster('TRUE',network='testrest1',cluster='RestCluster1') 2011-06-15 15:38:05,675 - networks - DEBUG - GET request content is -- url:http://localhost:8080/rhevm-api/networks 2011-06-15 15:38:05,887 - networks - DEBUG - Response body for GET request is: &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt; 2011-06-15 15:38:07,188 - rest-Main - INFO - Run test: yes 2011-06-15 15:38:07,188 - rest-Main - INFO - Test positive: TRUE </failure> </testcase> <testcase classname="qe-tests.network" name="Add network to iscsi" time="1"/> </testsuite> </testsuites> 

the beginning of the xml is as follows: (snippet) "Network" is just one of the possible children (for example, such as "Data Centers").

 <?xml version="1.0" encoding="UTF-8"?> <rest logfile="log.txt" testFile="REST_API.ods"> <Network> <test_parameters>name='RestDataCenter2',storage_type='iscsi',version='3.0'</test_parameters> <test_name>Add Network to cluster</test_name> <end_time>2011-06-13 01:22:56</end_time> <iter_num>70</iter_num> <test_positive>TRUE</test_positive> <tcms_test_case/> <start_time>2011-06-13 01:22:55</start_time> <status>Fail</status> </Network> <Network> <test_parameters>name='RestDataCenter2',storage_type='iscsi',version='3.0'</test_parameters> <test_name>Add network to iscsi</test_name> <end_time>2011-06-13 01:22:56</end_time> <iter_num>71</iter_num> <test_positive>TRUE</test_positive> <tcms_test_case/> <start_time>2011-06-13 01:22:55</start_time> <status>Pass</status> </Network> </rest> 
+4
source share
5 answers
  • Divide the log file into several log files before running xsl. each log file will be called "logfile.txt-X", where X is the iteration number. now all you have to do is print a specific log file:

<xsl:variable name="executionId" select="'70'"/>

<xsl:variable name="logfile" select="'logfile.txt'" />

<xsl:variable name="iter_log" select="concat($logfile,'-',$executionId)"/>

<xsl:variable name="output" select="unparsed-text($iter_log)">

<xsl:value-of select="$output" />

What do you think?

+1
source

I tried to solve this problem using for each group (or even a Muenchian grouping with keys) and failed because the population does not consist of nodes, and therefore many useful operations are not allowed.

The brute force method for emulating a “normal coding” cycle (ie, procedural) is to use recursion. But for this you need to be able to use the parameters. Then you define the “bool flag” by defining a boolean parameter and passing it a different value when you want to change it. Or even better, when you want to stop printing lines, just don't come back.

Here is the stylesheet:

 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <!-- $executionId is defined before and read from the xml, but for convenience: --> <xsl:variable name="executionId" select="'70'"/> <xsl:variable name="iter_line" select="concat('Iteration number: ',$executionId)"/> <xsl:variable name="logfile" select="'logfile.txt'" /> <xsl:template match="/"> <xsl:variable name="lines" select="tokenize(unparsed-text($logfile), '\r?\n')" /> <xsl:call-template name="search-for-start"> <xsl:with-param name="remaining-lines" select="$lines"/> </xsl:call-template> </xsl:template> <!-- skip lines until we find one that matches the start pattern --> <xsl:template name="search-for-start"> <xsl:param name="remaining-lines" select="()"/> <xsl:choose> <xsl:when test="contains($remaining-lines[1], $iter_line)"> <xsl:value-of select="$remaining-lines[1]"/> <xsl:text>&#x0a;</xsl:text> <xsl:call-template name="output-lines"> <xsl:with-param name="remaining-lines" select="$remaining-lines[position() > 1]"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:call-template name="search-for-start"> <xsl:with-param name="remaining-lines" select="$remaining-lines[position() > 1]"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- output the given lines, up to the next 'Iteration number: ' --> <xsl:template name="output-lines"> <xsl:param name="remaining-lines"/> <xsl:choose> <!-- If so, we're done. --> <xsl:when test="contains($remaining-lines[1], 'Iteration number: ')" /> <xsl:otherwise> <xsl:value-of select="$remaining-lines[1]"/> <xsl:text>&#x0a;</xsl:text> <xsl:call-template name="output-lines"> <xsl:with-param name="remaining-lines" select="$remaining-lines[position() > 1]"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> 

which, tested on your sample, gives: (after the prologue)

 2011-06-15 15:38:07,192 - rest-Main - INFO - Iteration number: 70 2011-06-15 15:38:07,187 - rest-Main - INFO - Test action: attachHostNic 2011-06-15 15:38:07,188 - rest-Main - INFO - Run test: yes 2011-06-15 15:38:07,188 - rest-Main - INFO - Test positive: TRUE 

which, I believe, is the desired outcome.

This does not seem like a very elegant solution, but I don’t know how to do it when the elements to be grouped are not nodes. Has anyone else got ideas?

+1
source

How about something like this:

 <xsl:variable name="lines" select="tokenize(unparsed-text($logfile), '\r?\n')"/> <xsl:variable name="start" select="f:find($lines 'Iteration 70')[1]"/> <xsl:variable name="end" select="f:find($lines, 'Iteration 71')[1]"/> <xsl:for-each select="subsequence($lines, $start, $end - $start + 1)"> ... </xsl:for-each> <xsl:function name="f:find" as="xs:integer*"> <xsl:param name="lines" as="xs:string*"/> <xsl:param name="content" as="xs:string"/> <xsl:for-each select="$lines"> <xsl:if test="contains(., content)"> <xsl:sequence select="position()"/> </xsl:if> </xsl:for-each> </xsl:function> 
+1
source

This conversion is :

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:variable name="vLines" as="xs:string*" select= "tokenize(/, '\r?\n')"/> <xsl:template match="/"> <xsl:sequence select= "for $x in my:procesStartStop($vLines, 'Iteration number: 70', 'Iteration number: 71') return ($x, '&#xA;') " /> </xsl:template> <xsl:function name="my:procesStartStop" as="xs:string*"> <xsl:param name="pLines" as="xs:string*"/> <xsl:param name="pStart" as="xs:string"/> <xsl:param name="pStop" as="xs:string"/> <xsl:sequence select= "for $len in count(($pLines, $pStop)), $start in (for $i in 1 to $len return if(contains($pLines[$i], $pStart)) then $i else() ) [1], $end in (for $j in 1 to $len return if(contains($pLines[$j], $pStop)) then $j else() ) [1] return subsequence($pLines, $start, $end -$start +1) "/> </xsl:function> </xsl:stylesheet> 

when applied to this XML document (containing the provided text):

 <t> 2011-06-15 15:38:07,126 - networks - INFO - Compared entities are equal 2011-06-15 15:38:07,152 - rest-Main - INFO - Test status for Pass 2011-06-15 15:38:07,187 - rest-Main - INFO - Test name: Attach Host NIC To Network 2011-06-15 15:38:07,192 - rest-Main - INFO - Iteration number: 70 2011-06-15 15:38:07,187 - rest-Main - INFO - Test action: attachHostNic 2011-06-15 15:38:07,188 - rest-Main - INFO - Run test: yes 2011-06-15 15:38:07,188 - rest-Main - INFO - Test positive: TRUE 2011-06-15 15:38:07,192 - rest-Main - INFO - Iteration number: 71 2011-06-15 15:38:07,188 - rest-Main - INFO - Test positive: DDDDD </t> 

creates the desired correct answer :

  2011-06-15 15:38:07,192 - rest-Main - INFO - Iteration number: 70 2011-06-15 15:38:07,187 - rest-Main - INFO - Test action: attachHostNic 2011-06-15 15:38:07,188 - rest-Main - INFO - Run test: yes 2011-06-15 15:38:07,188 - rest-Main - INFO - Test positive: TRUE 2011-06-15 15:38:07,192 - rest-Main - INFO - Iteration number: 71 
+1
source

How about this:

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="*"/> <xsl:param name="executionId" select="70"/> <xsl:param name="executionEnd" select="71"/> <xsl:template match="/"> <xsl:variable name="post70" select="tokenize( ., concat('Iteration number: ',$executionId,'\r?\n'),'m')[2]"/> <xsl:variable name="in7071" select="tokenize( $post70, concat('\r?\n.*Iteration number: ',$executionEnd,'\r?\n?'),'m')[1]"/> <xsl:value-of select="$in7071"/> </xsl:template> </xsl:stylesheet> 

It produces:

 2011-06-15 15:38:07,187 - rest-Main - INFO - Test action: attachHostNic 2011-06-15 15:38:07,188 - rest-Main - INFO - Run test: yes 2011-06-15 15:38:07,188 - rest-Main - INFO - Test positive: TRUE 
+1
source

All Articles