如何修改XSL以在XML转换中保留处理指令?
保留XML处理指令并同步元素重命名的XSL改造
需求背景
通过图形工具生成的XSL采用for-each和copy-of语法实现XML映射转换,但无法处理源XML新增的下游专用处理指令。需改造XSL满足:
- 复制元素时同步携带其与前一元素间的关联处理指令
- 保留未关联到目标元素的处理指令
- 元素重命名时同步更新对应处理指令的目标名称(如
favorite→preference)
原有XSL示例
<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:template match="/root"> <root> <xsl:for-each select="data"> <data> <xsl:copy-of select="id" /> <xsl:copy-of select="comment" /> <detail> <xsl:for-each select="detail"> <xsl:copy-of select="name" /> <preference> <xsl:value-of select="favorite" /> </preference> </xsl:for-each> </detail> </data> </xsl:for-each> </root> </xsl:template> </xsl:stylesheet>
含处理指令的源XML示例
<?xml version="1.0" encoding="UTF-8"?> <root> <data> <?format-number id?> <id>123</id> <?xml-multiple comment?> <?format-string comment?> <comment>hello</comment> <?format-string comment?> <comment>goodbye</comment> <?format-string text?> <text>bar</text> <detail> <?format-string name?> <name>bob</name> <?format-string favorite?> <favorite>cake</favorite> </detail> <?xml-multiple colors?> </data> </root>
预期转换结果
<?xml version="1.0" encoding="UTF-8"?> <root> <data> <?format-number id?> <id>123</id> <?xml-multiple comment?> <?format-string comment?> <comment>hello</comment> <?format-string comment?> <comment>goodbye</comment> <detail> <?format-string name?> <name>bob</name> <?format-string preference?> <preference>cake</preference> </detail> <?xml-multiple colors?> </data> </root>
改造后的XSL实现
<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:key name="rename-map" match="rename" use="@from"> <xsl:value-of select="@to"/> </xsl:key> <xsl:variable name="rename-rules"> <rename from="favorite" to="preference"/> </xsl:variable> <!-- 匹配处理指令,根据重命名规则更新目标名称 --> <xsl:template match="processing-instruction()"> <xsl:variable name="target" select="substring-after(., ' ')"/> <xsl:variable name="new-target" select="document('')//key('rename-map', $target)"/> <xsl:if test="$new-target != ''"> <xsl:processing-instruction name="{name()}"> <xsl:value-of select="substring-before(., ' ')"/> <xsl:text> </xsl:text> <xsl:value-of select="$new-target"/> </xsl:processing-instruction> </xsl:if> <!-- 无匹配重命名规则时直接复制 --> <xsl:if test="$new-target = ''"> <xsl:copy-of select="."/> </xsl:if> </xsl:template> <!-- 匹配所有元素,先复制前面的处理指令,再处理元素本身 --> <xsl:template match="*"> <!-- 复制当前元素之前、前一个元素之后的所有处理指令 --> <xsl:copy-of select="preceding-sibling::node()[not(self::*)][count(following-sibling::*) = count(following-sibling::*[generate-id()=generate-id(current())])]"/> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <!-- 复制属性 --> <xsl:template match="@*"> <xsl:copy/> </xsl:template> <!-- 根节点处理逻辑 --> <xsl:template match="/root"> <root> <xsl:for-each select="data"> <data> <!-- 处理id元素及关联指令 --> <xsl:apply-templates select="id"/> <!-- 处理comment元素及关联指令 --> <xsl:apply-templates select="comment"/> <detail> <xsl:for-each select="detail"> <!-- 处理name元素及关联指令 --> <xsl:apply-templates select="name"/> <!-- 处理favorite重命名为preference,同步处理指令 --> <xsl:apply-templates select="favorite"> <xsl:with-param name="new-name" select="'preference'"/> </xsl:apply-templates> </xsl:for-each> </detail> <!-- 复制data下未关联到目标元素的处理指令 --> <xsl:copy-of select="processing-instruction()[not(following-sibling::*[name()='id' or name()='comment' or name()='detail'])]"/> </data> </xsl:for-each> </root> </xsl:template> <!-- 处理需要重命名的元素 --> <xsl:template match="favorite"> <xsl:param name="new-name"/> <!-- 复制元素前的处理指令并更新目标名称 --> <xsl:apply-templates select="preceding-sibling::processing-instruction()[count(following-sibling::*) = count(following-sibling::*[generate-id()=generate-id(current())])]"/> <xsl:element name="{$new-name}"> <xsl:value-of select="."/> </xsl:element> </xsl:template> </xsl:stylesheet>
改造说明
- 处理指令匹配模板:单独匹配处理指令,通过预定义的重命名映射更新指令中的目标元素名称,无映射则直接复制。
- 元素处理模板:复制元素前的关联处理指令,再递归处理元素内容,确保指令随元素同步复制。
- 重命名元素处理:针对需要重命名的元素(如
favorite),先处理其关联的处理指令(更新目标名称),再生成新名称的元素。 - 孤立指令保留:在根节点处理逻辑中,复制未关联到任何目标元素的处理指令(如
<?xml-multiple colors?>)。
内容的提问来源于stack exchange,提问作者sparty02
相关产品推荐
相关产品推荐

