如何将内层元素状态传递到外层?XSLT技术实现问询
XSLT 根据内层元素状态生成外层错误标记解决方案
需求背景
基于此前Stack Overflow问题《XSLT: How to skip element when specific inner child element is missing?》的内容模型,需实现以下逻辑:
- 当
perf_data下的所有sample元素均不含value子元素时,在perf_data层级生成<Error>1</Error> - 否则生成
<Error>0</Error>
已完成忽略无效sample的模板编写,但因XSLT变量不可变特性,无法通过计数器实现外层判断逻辑,需解决方案。
输入示例
无效示例(Bad Sample)
<?xml version="1.0" encoding="utf-8"?> <MonitoringOutput id="id-3150" version="0.2"> <description>snmp_netif-1.out</description> <exit_code>0</exit_code> <status_string>Previous state not found, U octets/s in [delta 0s], U octets/s out [delta 0s]</status_string> <perf_string> in=U;;;0 out=U;;;0</perf_string> <perf_data count="2"> <sample label="in"> <label>in</label> <range min="0"/> </sample> <sample label="out"> <label>out</label> <range min="0"/> </sample> </perf_data> </MonitoringOutput>
有效示例(Good Sample)
<?xml version="1.0" encoding="utf-8"?> <MonitoringOutput id="id-3160" version="0.2"> <description>snmp_netif-2.out</description> <exit_code>0</exit_code> <status_string>bond0</status_string> <info_string>1560.23 octets/s in [delta 10s], 350.921 octets/s out [delta 10s]</info_string> <perf_string> in=1560.23B;;;0 out=350.921B;;;0</perf_string> <perf_data count="2"> <sample label="in"> <label>in</label> <value unit="B">1560.23</value> <unit>B</unit> <range min="0"/> </sample> <sample label="out"> <label>out</label> <value unit="B">350.921</value> <unit>B</unit> <range min="0"/> </sample> </perf_data> </MonitoringOutput>
解决方案
无需使用计数器,利用XPath节点存在性判断即可实现逻辑,分XSLT版本给出实现:
XSLT 1.0 实现
核心思路:通过not(sample/value)判断当前perf_data下是否没有任何sample包含value元素(若存在至少一个sample有value,该表达式返回false)。
完整XSLT代码:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 复制所有其他节点 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 处理perf_data节点 --> <xsl:template match="perf_data"> <xsl:copy> <!-- 复制原有属性 --> <xsl:apply-templates select="@*"/> <!-- 生成Error标记 --> <Error> <xsl:choose> <!-- 所有sample都没有value元素 --> <xsl:when test="not(sample/value)">1</xsl:when> <!-- 至少一个sample有value元素 --> <xsl:otherwise>0</xsl:otherwise> </xsl:choose> </Error> <!-- 应用原有sample处理模板(忽略无效sample) --> <xsl:apply-templates select="sample[value]"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
XSLT 2.0+ 实现
XSLT 2.0及以上支持every表达式,逻辑更直观:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 复制所有其他节点 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 处理perf_data节点 --> <xsl:template match="perf_data"> <xsl:copy> <xsl:apply-templates select="@*"/> <Error> <xsl:value-of select="if (every $s in sample satisfies not($s/value)) then 1 else 0"/> </Error> <xsl:apply-templates select="sample[value]"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
输出效果
- 无效示例处理后,
perf_data节点下会生成<Error>1</Error>,且无sample子节点(所有无效sample已被过滤) - 有效示例处理后,
perf_data节点下生成<Error>0</Error>,并保留含value的sample节点
内容的提问来源于stack exchange,提问作者U. Windl
相关产品推荐
相关产品推荐

