使用XSLT匹配属性值复制XML元素并修改内部指定属性值
XSLT提取指定节点并修改属性值实现方案
问题背景
现有如下结构的XML源文件,需要做指定节点提取和属性修改:
<?xml version="1.0" encoding="UTF-8"?> <FN> <START> <VALUE2><VALUE2> <VALUE3></VALUE3> <VALUE4></VALUE4> </START> <SET name="-RBS_00"> <DISH name="-00_01" QR="Buffer"> <OBJETS> <Ingredients total="3"> </Ingredients> </OBJETS> <Quantity> </Quantity> </DISH> <DISH name="-00_02" QR="RESTO"> <OBJETS meat="poulet"> <Ingredients total="5"></Ingredients> </OBJETS> <Quantity> <Adults numbers="4"> </Adults> <Kids numbers="3"> </Adults> </Quantity> </DISH> <DISH name="-00_03" QR="DELIVERY"> <OBJETS meat="jam"> <Slices total="3"></Slices> </OBJETS> <OBJETS meat="chicken"> <Slices total="5"></Slices> </OBJETS> <OBJETS meat="porc"> <Slices total="1"></Slices> </OBJETS> <Quantity> <Adults numbers="1"> </Adults> <Kids numbers="1"> </Adults> </Quantity> </DISH> <DISH name="-00_04" QR="KIDS"> <OBJETS meat="veggie"> <Ingredients total="11"></Ingredients> </OBJETS> <Quantity> <Adults numbers="10"> </Adults> <Kids numbers="2"> </Adults> </Quantity> </DISH> </SET> </FN>
需求说明
- 仅提取
name属性值为-00_03的完整<DISH>元素,丢弃其他所有无关节点 - 将提取到的DISH元素内部,所有
meat属性值为porc的项修改为meat="cheese"
最终输出XML结构如下:
<DISH name="-00_03" QR="DELIVERY"> <OBJETS meat="jam"> <Slices total="3"></Slices> </OBJETS> <OBJETS meat="chicken"> <Slices total="5"></Slices> </OBJETS> <OBJETS meat="cheese"> <Slices total="1"></Slices> </OBJETS> <Quantity> <Adults numbers="1"></Adults> <Kids numbers="1"></Adults> </Quantity> </DISH>
原有代码问题
之前编写的XSLT无法正常运行,问题出在两点:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="/FN/SET"> <xsl:copy> <xsl:copy-of select="*"/> <xsl:copy-of select="//DISH [@name='-00_03']"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
- 模板匹配
<SET>节点做全量复制,会带出所有外层节点和其他无关DISH内容,不符合仅输出目标DISH的要求 - 使用
xsl:copy-of做深拷贝是一次性复制所有内容,无法在复制过程中修改内部节点的属性值
实现代码(XSLT 1.0 全版本兼容)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <!-- 身份模板:默认原样复制所有匹配到的节点、属性、文本内容 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 根节点规则:跳过所有外层无关节点,只定位到目标DISH节点处理 --> <xsl:template match="/"> <xsl:apply-templates select="//DISH[@name='-00_03']"/> </xsl:template> <!-- 属性修改规则:匹配所有值为porc的meat属性,替换值为cheese --> <xsl:template match="@meat[.='porc']"> <xsl:attribute name="meat">cheese</xsl:attribute> </xsl:template> </xsl:stylesheet>
逻辑说明
- 身份模板是XSLT处理这类「大部分内容原样复制、少部分内容修改」需求的通用基础,会递归处理所有节点,不需要逐节点写复制逻辑
- 根节点处理规则直接过滤掉所有非目标内容,只把目标DISH节点送入后续处理流程
- 属性修改规则优先级高于身份模板,匹配到需要修改的meat属性时自动替换值,其余属性和节点全部按原样复制
内容的提问来源于stack exchange,提问作者runy29
相关产品推荐
相关产品推荐

