2010-11-09 58 views
2

在其他地方获得的属性值我跑CruiseControl.NET,我试图构建一个XSL样式表,提取有关从XML生成日志打破单元测试的某些信息。对于每一个损坏的单元测试,我想在XSL获得单元测试的名字,类名,其中所述单元测试驻留,并且失败消息。目前,我可以获得单元测试名称和失败消息,但我无法获取类名。我想这是因为单元测试的类名称仅包含在XML生成日志的不同区域,并且我在XSL一个小白。这里是我的XSL样式表的削减的样本:XSL到XML文档

<!-- Unit tests --> 
<xsl:template match="/"> 
<table border="1" width="100%"> 
    <tr> 
    <th align="left">Class</th> 
    <th align="left">Method</th> 
    <th align="left">Message</th> 
    </tr> 
    <xsl:apply-templates select="/cruisecontrol/build/*[local-name()='TestRun']/*[local-name()='Results']/*[local-name()='UnitTestResult']"/> 
</table> 
</xsl:template> 

<!-- Failed uint test --> 
<xsl:template match="*[local-name()='UnitTestResult'][@outcome='Failed']"> 
<tr> 
    <td> 
    <xsl:apply-templates select="/cruisecontrol/build/*[local-name()='TestRun']/*[local-name()='TestDefinitions']/*[local-name()='UnitTest'][@[email protected]]"/> 
    </td> 
    <td> 
    <xsl:value-of select="@testName"/> 
    </td> 
    <td> 
    <xsl:value-of select="*[local-name()='Output']/*[local-name()='ErrorInfo']/*[local-name()='Message']"/> 
    </td> 
</tr> 
</xsl:template> 

<!-- Failed unit test class name --> 
<xsl:template match="/cruisecontrol/build/*[local-name()='TestRun']/*[local-name()='TestDefinitions']/*[local-name()='UnitTest']"> 
<xsl:value-of select="@className"/> 
</xsl:template> 

这里被削减的样本XML生成日志:

<cruisecontrol> 
<build> 
    <TestRun> 
    <TestDefinitions> 
    <UnitTest name="MyUnitTest" storage="Test.dll" id="b17e5b2a-47d0-5f78-1750-07c8ac14518c"> 
    <TestMethod className="UnitTests.cs" name="MyUnitTest" /> 
    </UnitTest> 
    ... 
    </TestDefinitions> 
    <Results> 
    <UnitTestResult testId="b17e5b2a-47d0-5f78-1750-07c8ac14518c" testName="MyUnitTest" outcome="Failed"> 
    <Output> 
     <ErrorInfo> 
     <Message>Assert.AreEqual failed</Message> 
     </ErrorInfo> 
    </Output> 
    </UnitTestResult> 
    ... 
    </Results> 
    </TestRun> 
</build> 
</cruisecontrol> 

这里是电流输出:

单位测试课程名称:

单元测试方法名称:MyUnitTest

失败消息:Assert.AreEqual失败

这里是所期望的输出:

单元测试类名:UnitTests.cs

单元测试方法名称:MyUnitTest

失败消息:Assert.AreEqual失败

我的问题是类名永远是空的。我正在尝试使用UnitTestResult节点的testId属性在文档中的其他地方引用正确的UnitTest节点。我需要什么XSL或Xpath魔术来实现我的目标?

+0

为什么使用这些'local-name()'而不是直接节点名?假设没有XML命名空间(至少在你发布的XML中没有),'/ cruisecontrol/build/TestRun/Results/UnitTestResult'将等同于'/ cruisecontrol/build/* [local-name()= 'TestRun']/* [本地名称()= '结果']/* [本地名称()= 'UnitTestResult']'。 – Lucero 2010-11-09 16:31:37

+0

我不太确定;我在这方面是一个相当大的小事,并且正在接受别人以前的工作。感谢您的帮助和评论;将考虑改变这一点。我非常乐意提供进一步的建议,帮助他们清理并采用更好的做法。 – Sipp 2010-11-09 16:33:57

回答

2

在它看起来像这样乍一看是你的问题:

<xsl:apply-templates select="/cruisecontrol/build/*[local-name()='TestRun']/*[local-name()='TestDefinitions']/*[local-name()='UnitTest'][@[email protected]]"/> 

具体来说,[@[email protected]]部分。你试图基于其从UnitTestResulttestid属性id属性来查找UnitTest。问题是,在这种情况下[@[email protected]]的意思是“寻找单元测试的元素,其ID和testId属性相匹配。”

你真正想要的是使用current()功能,它允许你在过滤器中有一个以上的背景下,这样的:

[@id=current()/@testId] 

此外,像卢塞罗评论说,你要删除您的通话local-name(),因为它会让一切更简单:

<xsl:apply-templates 
    select="/cruisecontrol/build/TestRun/TestDefinitions/UnitTest[@id=current()/@testId]" 
/> 

作为替代使用长XPath表达式为您查询,您可以使用keys代替。他们让您定义一个密钥,稍后您可以使用该密钥进行较短的查找。

定义的关键是这样的:

<xsl:key 
    name="tests" 
    match="/cruisecontrol/build/TestRun/TestDefinitions/UnitTest" 
    use="@id"/> 

然后使用它是这样的:

<xsl:apply-templates select="key('tests',@testId)"/> 

这可以节省您不必使用电流()函数。无论哪种方式,它会工作。


使用local-name()函数可能表明您有名称空间问题。如果buildTestRun元素位于不同的名称空间中,则不能通过使用/cruisecontrol/build/TestRun/来简单地查询它们。这将只从默认命名空间查询元素。如果TestRun位于另一个命名空间中,则需要在XSLT文件中定义该命名空间,并在您的表达式中使用其前缀,如下所示:/cruisecontrol/build/ns:TestRun其中ns是有问题的命名空间前缀。 local-name()所做的是忽略元素名称的命名空间部分,绕过正确定义命名空间。当您不知道源文档中将使用哪些名称空间时,它也很有用。

+0

有趣; 节点是节点的子节点。构建节点不指定名称空间,但TestRun节点确实: xmlns =“http://microsoft.com/schemas/VisualStudio/TeamTest/2006” 这是否意味着它们位于不同的命名空间中? – Sipp 2010-11-09 17:12:08

+0

@Dark Lord:是的。 xmlns =“foo”是一个*默认命名空间声明*,意味着这个和所有没有命名空间前缀的后代元素都在“foo”命名空间中。因此''在TeamTest命名空间中,但''不是。 – LarsH 2010-11-09 17:20:13

+0

真棒,感谢Welbog和LarsH,我按照预期工作。通过在样式表顶部定义TeamTest名称空间,我解决了名称空间问题。除此之外,我不得不为名称空间下的节点使用名称空间和本地名称函数。看到它的工作是光荣的。再次感谢您的帮助! – Sipp 2010-11-09 18:05:31