我正在通过 xslt 读取外部日志文件,我想找到某一行。
一旦我找到它,我想打印所有的行,直到我打到另一行。
我需要为一个非常大的日志文件重复执行此操作。
每次迭代都有一个唯一的 id,日志文件通过以下方式分隔相关信息
“迭代次数:X”直到“迭代次数X+1”(或EOF)。
这是我的 xsl:(相关代码在故障标签中)
<?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>
我更新了代码以使用@empo 解决方案,但以这种方式使用 xsl:param 时出现错误。
我拥有的日志文件是这样的(这是一个简化的片段)
(在本例中,从“迭代 70”行开始并在迭代 71 行停止)
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
所需的 xml 输出如下所示:(仅在失败时才会显示详细输出)
<?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: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
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>
原始 xml 看起来像这样:(片段)
“网络”只是一个可能的 child (例如,还有更像“数据中心”)
<?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>
最佳答案
我尝试使用 for-each-group(或者甚至使用键的 Muenchian 分组)来解决这个问题,但失败了,因为人口不包含节点,因此不允许进行如此多的有用操作。
模拟“正常编码”(即程序)循环的蛮力方法是使用递归。但是要做到这一点,您需要能够使用参数。然后,您可以通过定义一个 bool 参数来“定义一个 bool 标志”,并在您想要更改它时为其传递一个不同的值。或者更好的是,当您想停止打印行时,不要递归。
这是样式表:
<?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>
</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>
</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>
其中,在您的示例输出上进行测试,给出:(在序言之后)
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
我相信这是所需的输出。
这似乎不是一个非常优雅的解决方案,但是当要分组的项目不是节点时,我不知道该怎么做。其他人有想法吗?
关于xslt - 如何在 xslt 中设置标志/变量以再次输入(与转换为 Junit 格式有关),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6366241/