XSL转换问题:如何获取CPU、Memory指标的最值及对应时间
嘿,没问题,我来帮你搞定这个XSLT转换需求——从你的XML数据里提取指定<sample>元素的<value>最值,以及对应的@time属性值,最终输出成清晰的HTML表格。下面分两种常见的XSLT版本给出可运行的解决方案:
方案1:XSLT 2.0(推荐,语法更简洁直观)
适合支持XSLT 2.0及以上的处理器(比如Saxon),代码逻辑清晰,容易维护:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" encoding="UTF-8" indent="yes"/> <xsl:template match="/root"> <html> <body> <table border="1"> <tr> <th>监控类型</th> <th>最小值</th> <th>最小值对应时间</th> <th>最大值</th> <th>最大值对应时间</th> </tr> <!-- 分组:将含cpu的归为一组,memory单独一组 --> <xsl:for-each-group select="sample[@label = 'memory' or contains(@label, 'cpu')]" group-by="if (contains(@label, 'cpu')) then 'cpu组' else @label"> <tr> <td><xsl:value-of select="current-grouping-key()"/></td> <!-- 计算当前组的最小值 --> <xsl:variable name="min-val" select="min(current-group()/value)"/> <td><xsl:value-of select="$min-val"/></td> <td><xsl:value-of select="current-group()[value = $min-val]/@time"/></td> <!-- 计算当前组的最大值 --> <xsl:variable name="max-val" select="max(current-group()/value)"/> <td><xsl:value-of select="$max-val"/></td> <td><xsl:value-of select="current-group()[value = $max-val]/@time"/></td> </tr> </xsl:for-each-group> </table> </body> </html> </xsl:template> </xsl:stylesheet>
关键逻辑说明:
- 用
@label = 'memory' or contains(@label, 'cpu')精准筛选目标<sample>元素 - 通过
group-by将所有含cpu的样本归为同一组,memory样本单独成组 - 用
min()/max()直接计算组内<value>的最值,再通过current-group()[value = 最值]定位到对应节点,提取@time
方案2:XSLT 1.0(兼容老版本处理器)
如果你的环境只支持XSLT 1.0(比如旧版的MSXML),可以用Muenchian分组法实现,代码如下:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" encoding="UTF-8" indent="yes"/> <!-- 定义分组键:按cpu组/memory分组 --> <xsl:key name="sample-group" match="sample[@label = 'memory' or contains(@label, 'cpu')]" use="if (contains(@label, 'cpu')) then 'cpu组' else @label"/> <xsl:template match="/root"> <html> <body> <table border="1"> <tr> <th>监控类型</th> <th>最小值</th> <th>最小值对应时间</th> <th>最大值</th> <th>最大值对应时间</th> </tr> <!-- 遍历唯一分组键 --> <xsl:for-each select="sample[@label = 'memory' or contains(@label, 'cpu')] [generate-id() = generate-id(key('sample-group', if (contains(@label, 'cpu')) then 'cpu组' else @label)[1])]"> <xsl:variable name="group-key" select="if (contains(@label, 'cpu')) then 'cpu组' else @label"/> <xsl:variable name="current-group" select="key('sample-group', $group-key)"/> <tr> <td><xsl:value-of select="$group-key"/></td> <!-- 计算最小值:对组内value排序后取第一个 --> <xsl:variable name="sorted-min"> <xsl:for-each select="$current-group"> <xsl:sort select="value" data-type="number" order="ascending"/> <xsl:if test="position() = 1"> <time><xsl:value-of select="@time"/></time> <val><xsl:value-of select="value"/></val> </xsl:if> </xsl:for-each> </xsl:variable> <td><xsl:value-of select="$sorted-min/val"/></td> <td><xsl:value-of select="$sorted-min/time"/></td> <!-- 计算最大值:对组内value排序后取最后一个 --> <xsl:variable name="sorted-max"> <xsl:for-each select="$current-group"> <xsl:sort select="value" data-type="number" order="descending"/> <xsl:if test="position() = 1"> <time><xsl:value-of select="@time"/></time> <val><xsl:value-of select="value"/></val> </xsl:if> </xsl:for-each> </xsl:variable> <td><xsl:value-of select="$sorted-max/val"/></td> <td><xsl:value-of select="$sorted-max/time"/></td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet>
关键逻辑说明:
- 用
<xsl:key>定义分组规则,实现类似XSLT 2.0的分组效果 - 通过
generate-id()判断当前节点是否是分组的第一个节点,避免重复处理 - 对组内节点按
<value>排序,取第一个(最小值)或最后一个(最大值)节点,提取对应的@time和<value>
测试用XML示例(补全你提供的片段)
<?xml version="1.0" encoding="UTF-8"?> <root> <sample time="14" label="cpu_0"><value>22</value></sample> <sample time="14" label="cpu_2"><value>6</value></sample> <sample time="1" label="cpu_2"><value>4</value></sample> <sample time="5" label="memory"><value>1024</value></sample> <sample time="8" label="memory"><value>2048</value></sample> <sample time="3" label="cpu_1"><value>15</value></sample> </root>
转换后HTML效果
最终生成的HTML表格会是这样:
监控类型 最小值 最小值对应时间 最大值 最大值对应时间 cpu组 4 1 22 14 memory 1024 5 2048 8
额外提示
如果存在多个节点的<value>等于最值(比如两个不同时间的cpu样本value都是4),你可以修改代码输出所有对应的时间:
- XSLT 2.0:把
<xsl:value-of select="current-group()[value = $min-val]/@time"/>改成<xsl:value-of select="current-group()[value = $min-val]/@time" separator=", "/> - XSLT 1.0:用
<xsl:for-each>遍历所有符合条件的节点,拼接@time值
内容的提问来源于stack exchange,提问作者Jakub Oškera
相关产品推荐
相关产品推荐

