基于XSLT 1.0提取XML中value1最大值对应的Test节点
XSLT 1.0筛选value1最大值对应的Test节点
我正在编写XSLT 1.0样式表,需要处理如下XML:从所有<Test>节点中找出value1字段值最大的节点,输出该节点下所有子标签,同时保留原XML的根结构。
请求XML
<?xml version="1.0" encoding="UTF-8"?> <GetTestValues xmlns="http://www.test.com/GetTestValues"> <TestSample> <Test> <value1>10000</value1> <value2>2016-01-28</value2> <value3>2017-12-10T01:36:12.403+00:00</value3> <value4>US</value4> <value5>true</value5> </Test> <Test> <value1>30000</value1> <value2>2019-01-28</value2> <value3>2019-01-28T18:04:13.763+00:00</value3> <value4>Canada</value4> <value5>false</value5> </Test> <Test> <value1>50000</value1> <value2>2019-01-28</value2> <value3>2019-01-28T18:04:13.763+00:00</value3> <value4>Canada</value4> <value5>false</value5> </Test> </TestSample> </GetTestValues>
期望输出
<?xml version="1.0" encoding="UTF-8"?> <GetTestValues xmlns="http://www.test.com/GetTestValues"> <TestSample> <Test> <value1>50000</value1> <value2>2019-01-28</value2> <value3>2019-01-28T18:04:13.763+00:00</value3> <value4>Canada</value4> <value5>false</value5> </Test> </TestSample> </GetTestValues>
尝试的代码及问题
我尝试用<xsl:for-each>遍历所有Test节点,但会输出全部内容,不知道如何比较并筛选出value1值最大的节点。尝试的代码如下:
<xsl:for-each select="/ns0:GetTestValues/ns0:TestSample/ns0:Test"> <ns0:value1> <xsl:value-of select="ns0:value1"/> </ns0:value1> <ns0:value2> <xsl:value-of select="ns0:value2"/> </ns0:value2> <ns0:value3> <xsl:value-of select="ns0:value3"/> </ns0:value3> <ns0:value4> <xsl:value-of select="ns0:value4"/> </ns0:value4> <ns0:value5> <xsl:value-of select="ns0:value5"/> </ns0:value5> </xsl:for-each>
解决方案
XSLT 1.0没有内置的max()函数,可通过以下两种方法实现需求:
方法1:排序后取首个节点
利用<xsl:sort>对Test节点按value1降序排序,仅输出第一个节点:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://www.test.com/GetTestValues"> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <xsl:template match="/ns0:GetTestValues"> <ns0:GetTestValues> <ns0:TestSample> <xsl:for-each select="ns0:TestSample/ns0:Test"> <!-- 按value1数字值降序排序 --> <xsl:sort select="ns0:value1" data-type="number" order="descending"/> <!-- 只保留第一个排序后的节点 --> <xsl:if test="position() = 1"> <xsl:copy-of select="."/> </xsl:if> </xsl:for-each> </ns0:TestSample> </ns0:GetTestValues> </xsl:template> </xsl:stylesheet>
方法2:用节点谓词直接筛选
通过谓词判断当前节点的value1是否大于等于所有其他Test节点的value1:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://www.test.com/GetTestValues"> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <xsl:template match="/ns0:GetTestValues"> <ns0:GetTestValues> <ns0:TestSample> <!-- 筛选value1为最大值的Test节点 --> <xsl:copy-of select="ns0:TestSample/ns0:Test[ns0:value1 >= ../ns0:Test/ns0:value1]"/> </ns0:TestSample> </ns0:GetTestValues> </xsl:template> </xsl:stylesheet>
关键说明
- 必须正确绑定命名空间
ns0,对应原XML的http://www.test.com/GetTestValues; - 排序时指定
data-type="number",避免字符串排序导致的错误(如"10000"字符串排序会落后于"5000"); - 方法1直观易懂,适合节点数量较少的场景;方法2无需排序,性能更优。
内容的提问来源于stack exchange,提问作者Krishna
相关产品推荐
相关产品推荐

