使用XSLT基于后代节点值创建曾孙节点的实现方案咨询
解决方案
你遇到的核心问题有两个:一是无命名空间源节点复制到带命名空间的父节点下时自动生成xmlns=""声明,二是手动字符串拆分id的写法冗余且效率较低。以下是优化后的XSLT 3.0实现:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" xmlns="http://www.loc.gov/mods/v3" xpath-default-namespace=""> <xsl:output omit-xml-declaration="no" indent="yes"/> <xsl:mode on-no-match="shallow-copy"/> <!-- 根节点处理,指定目标命名空间 --> <xsl:template match="foo"> <foo> <xsl:apply-templates/> </foo> </xsl:template> <!-- 处理blah节点,添加新元素 --> <xsl:template match="blah"> <xsl:copy> <!-- 复制blah下所有现有子节点,自动转换到目标命名空间 --> <xsl:apply-templates select="@*, node()"/> <!-- 拆分id,直接取第1和第3段 --> <xsl:variable name="idParts" select="tokenize(ancestor::record/header/id, '-')"/> <new-element>The value <xsl:value-of select="$idParts[1]"/> and <xsl:value-of select="$idParts[3]"/> came from the id element</new-element> </xsl:copy> </xsl:template> </xsl:stylesheet>
优化点说明
- 命名空间问题解决:通过
xpath-default-namespace=""声明源XML节点无命名空间,结合xsl:mode的浅复制规则,所有复制的节点都会自动继承样式表声明的默认MODS命名空间,不会再生成多余的xmlns=""空命名空间声明。 - id拆分优化:使用XSLT 2.0+内置的
tokenize函数按-直接拆分id为数组,不用嵌套多层字符串截取函数,代码更简洁,执行效率更高。 - 通用复制逻辑:用
xsl:mode on-no-match="shallow-copy"实现自动遍历复制所有未匹配到自定义模板的节点,不用手动写每一层节点的复制逻辑,代码可维护性更强,源XML结构调整时无需大幅修改样式表。
该实现完全兼容Saxon 10.6,转换后的输出和你预期的效果完全一致,大文件场景下性能远优于手动逐层复制节点的实现。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

