我正在尝试编写XSL,将我的XML转换为jenkins采取的JUNIT格式(请参见下文)
我的xml看起来像这样:(我有几个“类”,例如“数据中心”或“网络”)
<tests> <Datacenters> <test_name>Create NFS Data Center</test_name> <end_time>2011-06-13 01:22:55</end_time> <iter_num>1</iter_num> <start_time>2011-06-13 01:22:52</start_time> <status>Pass</status> </Datacenters> <Datacenters> <test_name>Create NFS Data Center</test_name> <end_time>2011-06-13 01:22:55</end_time> <iter_num>1</iter_num> <start_time>2011-06-13 01:22:52</start_time> <status>Pass</status> </Datacenters> <Network> <test_name>Network test 1</test_name> <end_time>2011-06-13 01:22:57</end_time> <iter_num>1</iter_num> <start_time>2011-06-13 01:22:52</start_time> <status>Pass</status> </Network> ..... </tests>
我从WebUI插件中获取了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> <! -- need to change /Datacenters to something else so it will work on all nodes --> <xsl:variable name="buildName" select="//tests/Datacenters/test_name"/> <xsl:variable name="numOfTests" select="count(//tests/Datacenters/iter_num)"/> <xsl:variable name="numOfFail" select="count(//tests/Datacenters/status [.= 'Fail'])" /> <xsl:variable name="numberSkip" select="count(//tests/Datacenters/status [.!='Pass' and .!='Fail'])" /> <testsuite name="QE AUTOMATION TESTS [DATACENTERS]" tests="{$numberOfTests}" time="0" failures="{$numberOfFailures}" errors="0" skipped="{$numberSkipped}"> <xsl:for-each select="//rest/Datacenters"> <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"/> <!--<xsl:variable name="className" select="Data"/> --> <testcase classname="Datacenters" name="{$testName}" time="{$duration_hours*3600 + $duration_minutes*60 + $duration_seconds }"> <xsl:if test="contains($outcome, 'Fail')"> <failure> test_parameters: <xsl:value-of select="$test_parameters" /> test_positive: <xsl:value-of select="$test_positive" /> </failure> </xsl:if> </testcase> </xsl:for-each> </testsuite> </testsuites> </xsl:template> </xsl:stylesheet>
我要实现的是这个xml:
<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="Datacenters" tests="2" time="4" failures="0" errors="0" skipped="0"> <testcase classname="Datacenters" name="Create NFS Data Center" time="3"/> <testcase classname="Datacenters" name="Create ISCSI Data Center" time="1"/> </testsuite> <testsuite name="Network" tests="1" time="5" failures="0" errors="0" skipped="0"> <testcase classname="Datacenters" name="Network test 1" time="5"/> </testsuite> </testsuites>
但我不知道如何在所有“类”上进行迭代,因此我希望它不呈现“数据中心”的所有现有子级,而不是对其进行硬编码 <tests>
<tests>
我只想回答模板中的注释(您的代码可能需要调试和重构):
<!-- need to change /Datacenters to something else so it will work on all nodes -->
为了避免硬编码:
1) 像这样替换XPath:
//tests/Datacenters/test_name
与 //tests/*/test_name
//tests/*/test_name
2) 修正迭代(完全错误),应为:
<xsl:for-each select="//tests/Datacenters">
而你想要:
<xsl:for-each select="//tests/*">
3) 最后,请更换:
<testcase classname="Datacenters">
与
<testcase classname="{local-name(.)}">
评论后编辑
我将以简化的输出进行回答,只是向您展示 XSLT 2.0中 分组的工作方式。希望这个答案对您来说是可以接受的,您的实际模板在这里很难测试:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output indent="yes"/> <xsl:template match="tests"> <testsuites> <xsl:for-each-group select="*" group-by="local-name()"> <testsuite name="{current-grouping-key()}"> <xsl:for-each select="current-group()"> <testcase classname="{current-grouping-key()}"/> </xsl:for-each> </testsuite> </xsl:for-each-group> </testsuites> </xsl:template> </xsl:stylesheet>
应用于问题中提供的输入样本,将产生:
<?xml version="1.0" encoding="UTF-8"?> <testsuites> <testsuite name="Datacenters"> <testcase classname="Datacenters"/> <testcase classname="Datacenters"/> </testsuite> <testsuite name="Network"> <testcase classname="Network"/> </testsuite> </testsuites>