XSLT转换需求:合并同<namepf>的<record>错误信息
XSLT 同错误合并实现方案
输入输出样例参考
输入XML
<root> <record> <namepf>Alice</namepf> <email status="error">invalid-email</email> <phone>123456</phone> </record> <record> <namepf>Alice</namepf> <address status="error">missing-street</address> </record> <record> <namepf>Bob</namepf> <phone status="error">invalid-number</phone> </record> </root>
期望输出XML
<root> <record> <namepf>Alice</namepf> <errors> <email status="error">invalid-email</email> <address status="error">missing-street</address> </errors> <phone>123456</phone> </record> <record> <namepf>Bob</namepf> <errors> <phone status="error">invalid-number</phone> </errors> </record> </root>
核心实现思路
- 按
<namepf>元素的值对所有<record>分组 - 每个分组生成一个目标
<record>节点,保留该组的<namepf>标识 - 收集分组内所有
<record>中带错误状态的子元素,统一放入同一个<errors>标签 - 按需保留分组内基准
<record>的非错误节点
修改后的XSLT代码
XSLT 1.0 版本(兼容旧版处理器)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 定义分组key:按namepf的值匹配record --> <xsl:key name="record-group" match="record" use="namepf"/> <xsl:template match="/"> <root> <!-- 遍历每个分组的第一个record作为基准 --> <xsl:for-each select="root/record[generate-id() = generate-id(key('record-group', namepf)[1])]"> <record> <!-- 复制当前分组的namepf --> <xsl:copy-of select="namepf"/> <!-- 合并分组内所有错误元素 --> <errors> <xsl:copy-of select="key('record-group', namepf)//*[@status='error']"/> </errors> <!-- 复制基准record中的非错误、非namepf节点 --> <xsl:copy-of select="*[not(@status='error') and local-name()!='namepf']"/> </record> </xsl:for-each> </root> </xsl:template> </xsl:stylesheet>
XSLT 2.0+ 版本(语法更简洁)
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <root> <!-- 按namepf分组处理 --> <xsl:for-each-group select="root/record" group-by="namepf"> <record> <!-- 复制分组内第一个record的namepf --> <xsl:copy-of select="current-group()[1]/namepf"/> <!-- 收集分组内所有错误元素 --> <errors> <xsl:copy-of select="current-group()//*[@status='error']"/> </errors> <!-- 复制基准record的非错误节点 --> <xsl:copy-of select="current-group()[1]/*[not(@status='error') and local-name()!='namepf']"/> </record> </xsl:for-each-group> </root> </xsl:template> </xsl:stylesheet>
自定义调整说明
- 如果错误标记不是
@status='error'(比如固定标签名<error>),将//*[@status='error']改为//error即可 - 若需要合并分组内所有非错误节点而非仅基准节点,可将
<xsl:copy-of select="current-group()[1]/*..."/>改为<xsl:copy-of select="current-group()/*[not(@status='error') and local-name()!='namepf']"/> - 若不需要保留非错误节点,直接删除对应
<xsl:copy-of>语句即可
内容的提问来源于stack exchange,提问作者TulioVargas
相关产品推荐
相关产品推荐

