如何使用XSLT基于子字符串对XML数据进行分组
解决XML元素按名称子字符串分组的XSLT问题
问题描述
我想用XSLT把XML文档里的数据分成两类——建筑和食物。现有三个条目,希望通过元素名的子字符串来分组归类。
原始XML
<?xml version="1.0" encoding="UTF-8"?> <items> <Skyscraper>Willis Tower</Skyscraper> <Small_fruit>blueberry</Small_fruit> <Big_fruit>watermelon </Big_fruit> </items>
最初尝试的XSLT
<?xml version="1.1" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0"> <xsl:output method="xml"/> <xsl:template match = "/"> <items> <xsl:element name = "Fruit"> <xsl:for-each-group select="//items" group-by="*[contains(local-name(), 'fruit')]"> <xsl:copy-of select = "."/> <xsl:value-of select="current-grouping-key()"/> <xsl:if test = "not(position() = last())">,</xsl:if> </xsl:for-each-group> </xsl:element> </items> </xsl:template> </xsl:stylesheet>
期望输出XML
<?xml version="1.0" encoding="UTF-8"?> <items> <Building> <Skyscraper>Willis Tower</Skyscraper> </Building> <Food> <Small_fruit>blueberry</Small_fruit> <Big_fruit>watermelon </Big_fruit> </Food> </items>
修改后的XSLT(仍有问题)
<?xml version="1.1" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0"> <!-- airport XSLT --> <xsl:output method="xml"/> <xsl:template match = "/"> <items> <xsl:element name = "fruit"> <xsl:for-each-group select="/items/*" group-by="*[contains(local-name(), 'fruit')]"> <xsl:copy-of select = "."/> <xsl:value-of select="current-grouping-key()"/> <xsl:if test = "not(position() = last())">
</xsl:if> </xsl:for-each-group> </xsl:element> <xsl:element name = "building"> <xsl:for-each-group select="/items/*" group-by="*[contains(local-name(), 'sky')]"> <xsl:copy-of select = "."/> <xsl:value-of select="current-grouping-key()"/> <xsl:if test = "not(position() = last())">
</xsl:if> </xsl:for-each-group> </xsl:element> </items> </xsl:template> </xsl:stylesheet>
正确的XSLT解决方案
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <items> <!-- 按元素名特征分组:含'fruit'归Food组,其余归Building组 --> <xsl:for-each-group select="/items/*" group-by="if (contains(local-name(), 'fruit')) then 'Food' else 'Building'"> <xsl:element name="{current-grouping-key()}"> <xsl:copy-of select="current-group()"/> </xsl:element> </xsl:for-each-group> </items> </xsl:template> </xsl:stylesheet>
方案说明
- 一次性遍历所有子元素
/items/*,避免重复扫描节点 - 用条件表达式作为分组键,直接将元素归类到
Food或Building组 - 为每个分组创建对应名称的外层元素,复制组内所有原始元素,保留原有结构
- 开启
indent="yes"让输出格式与期望结果一致,更易读 - 移除了多余的文本输出逻辑,确保结果纯净
内容的提问来源于stack exchange,提问作者n718an
相关产品推荐
相关产品推荐

