XSLT实现:移除重复status元素,保留最新timestamp的entry
问题:移除重复status的entry元素,仅保留最新timestamp的条目
原始XML如下:
<root> <entry> <status>On Time</status> <timestamp>2022-06-16T00:00:00Z</timestamp> </entry> <entry> <status>On Time</status> <timestamp>2022-06-24T00:00:00Z</timestamp> </entry> <entry> <status>On Time</status> <timestamp>2022-07-07T00:00:00Z</timestamp> </entry> <entry> <status>Late</status> <timestamp>2022-08-05T00:00:00Z</timestamp> </entry> <entry> <status>Delivered</status> <timestamp>2022-09-02T00:00:00Z</timestamp> </entry> <entry> <status>On Time</status> <timestamp>2022-06-13T00:00:00Z</timestamp> </entry> <entry> <status>Late</status> <timestamp>2022-08-01T00:00:00Z</timestamp> </entry> <entry> <status>Late</status> <timestamp>2022-07-03T00:00:00Z</timestamp> </entry> <entry> <status>On Time</status> <timestamp>2022-06-13T00:00:00Z</timestamp> </entry> </root>
需求:移除所有具有重复<status>值的<entry>元素,仅保留每个status对应的timestamp为最新(xs:dateTime类型)的条目。元素随机排序,<root>下可能包含多种其他status类型,期望输出如下:
<root> <entry> <status>On Time</status> <timestamp>2022-07-07T00:00:00Z</timestamp> </entry> <entry> <status>Late</status> <timestamp>2022-08-05T00:00:00Z</timestamp> </entry> <entry> <status>Delivered</status> <timestamp>2022-09-02T00:00:00Z</timestamp> </entry> </root>
解决方案:XSLT实现代码
XSLT 2.0+版本实现
利用分组和原生排序功能,代码更简洁:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xsl:output method="xml" indent="yes"/> <xsl:template match="root"> <xsl:copy> <!-- 按status值对entry分组 --> <xsl:for-each-group select="entry" group-by="status"> <!-- 把组内entry按timestamp降序排序(最新时间在前) --> <xsl:sort select="xs:dateTime(timestamp)" order="descending"/> <!-- 复制组内第一个元素(即最新时间的条目) --> <xsl:copy-of select="current-group()[1]"/> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet>
XSLT 1.0版本实现
使用Muenchian分组法兼容旧版本:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 定义分组键,按status关联entry --> <xsl:key name="status-group" match="entry" use="status"/> <xsl:template match="root"> <xsl:copy> <!-- 选取每个status组的首个元素作为分组标识 --> <xsl:for-each select="entry[generate-id() = generate-id(key('status-group', status)[1])]"> <!-- 遍历当前组内所有entry,按timestamp降序排序 --> <xsl:for-each select="key('status-group', status)"> <xsl:sort select="timestamp" order="descending"/> <!-- 仅输出排序后的第一个元素 --> <xsl:if test="position() = 1"> <xsl:copy-of select="."/> </xsl:if> </xsl:for-each> </xsl:for-each> </xsl:copy> </xsl:template> </xsl:stylesheet>
内容的提问来源于stack exchange,提问作者Tanner B
相关产品推荐
相关产品推荐

