问题
如何利用XSL提供由运行的代码确定的条件格式(例如,表行之间的增加或减少)?
背景
编辑: 这是一个背景服务实现,使用ASP.NET Core作为长期运行的服务的主机运行,该服务对外部资源的运行状况进行审核。这可能是.NET Core缺少.NET Framework中存在的某些功能的问题,因此我认为值得一提
这个想法之所以开始,是因为我一直在寻找一种方法来制作一个简单的HTML模板,可以以一种简单而有效的方式将我的C#数据对象映射到该模板,而无需处理StringBuilder。在这种希望中,我发现this StackOverflow response表示XSLT是一个很好的解决方案,而无需执行完整的MVC方法。
这就是一切的开始(为简洁起见):
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" encoding="utf-8"/>
<xsl:template match='/Email'>
<html>
<head>
<style>
<xsl:value-of select="Styles"/>
</style>
</head>
<body>
<h1>Total</h1>
<table id="tblTotal" class="clsPositive">
<tr>
<th>Audit Date</th>
<th>Source 1</th>
<th>Source 2</th>
...
</tr>
<xsl:for-each select="Total/ArrayOfElement/AuditElement">
<xsl:sort select="ReportDate" order="descending"/>
<tr>
<td><xsl:value-of select="ReportDate"/></td>
<td><xsl:value-of select="Source1CountFormatted"/> (<xsl:value-of select="Source1GrowthFormatted"/>)</td>
<td><xsl:value-of select="Source2CountFormatted"/> (<xsl:value-of select="Source2GrowthFormatted"/>)</td>
...
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
有了这个,我有了一个想法,可以根据表示的数据类型有条件地格式化增长率(您可以在表的class属性中看到它的开头,我用来确定是增加还是减少)是正面还是负面)。但是,当我尝试执行此操作时,Visual Studio告诉我XSL格式错误:
<td><xsl:value-of select="Source1CountFormatted"/> (<i class="<xsl:value-of select="Source1GrowthCss"/>"><xsl:value-of select="Source1GrowthFormatted"/> </i>)</td>
我还尝试了一种方法,其中“ ... GrowthFormatted”属性将返回其内联样式,但是在解析为要转换的XML树时,所有HTML都会立即转义。在来到这里之前,我最后的尝试是使用xsl:text方法,并且将disable-output-escaping:“ yes”。这导致了XSL的怪异(请注意两种不同的方法来查看它是否完全可以工作):
<td><xsl:value-of select="Source1CountFormatted"/> (<xsl:text disable-output-escaping="yes"><</xsl:text>i class=<xsl:text disable-output-escaping="yes">"</xsl:text><xsl:value-of select="Source1GrowthCssClass"/><xsl:text disable-output-escaping="yes">"></xsl:text><xsl:value-of select="Source1GrowthFormatted"/><xsl:text disable-output-escaping="yes"><</xsl:text>/i<xsl:text disable-output-escaping="yes">></xsl:text>)</td>
<td><xsl:value-of select="Source2CountFormatted"/> (<xsl:text disable-output-escaping="yes"><i class="</xsl:text><xsl:value-of select="Source2GrowthCssClass"/><xsl:text disable-output-escaping="yes">"></xsl:text><xsl:value-of select="Source2GrowthFormatted"/><xsl:text disable-output-escaping="yes"></i></xsl:text>)</td>
你们中间的鹰眼甚至可能注意到我使用了<xsl:text disable-output-escaping="yes"><</xsl:text>
的{{3}}提供的教科书示例,您可能会问,结果是什么?好吧,Visual Studio没错,因为嵌套元素不能与XSL一起很好地工作,并引发了以下异常:
XslLoadException: XSLT compile error. An error occurred at , (66, 84). ---> System.Xml.XmlException: '<', hexadecimal value 0x3C is an invalid attribute character. Line 66, poisition 84.
对于极其冗长的方法以及超级简单的方法,它们都导致生成以下HTML:
...
<tr>
<td>2019-09-19 12:30:40Z</td>
<td>35,991,744 (<i class="clsDecrease">0.00%</i>)</td>
<td>755,412 (<i class="clsDecrease">0.00%</i>)</td>
...
答案 0 :(得分:1)
这里的语法是错误的:
<i class="<xsl:value-of select="Source1GrowthCss"/>">
要动态设置属性值,可以使用xsl:attribute
,如下所示:
<i>
<xsl:attribute name="class">
<xsl:value-of select="Source1GrowthCss"/>
</xsl:attribute>
</i>
但是这很漫长。理想的方法是使用“属性值模板”,它更干净
<i class="{Source1GrowthCss}">
在这里,花括号表示要对表达式求值,而不是按字面意思输出。