如何让XSLT 2.0模板同时处理XML原生元素与动态生成元素?
解决XSLT 2.0中原生元素与动态生成元素共享转换流程的问题
输入XML
<?xml version="1.0" encoding="UTF-8"?> <document> <h2>General Introduction</h2> <h3>Project Overview</h3> <h3>Goals and Challenges</h3> <h2>Installation</h2> <h3>Initial Configuration</h3> <h4>Configuration File</h4> <h3>Deployment</h3> <h4>On a Local Server</h4> <h4>On a Remote Server</h4> <h2>Usage</h2> <h3>Basic Commands</h3> <h3>Advanced Options</h3> </document>
现有XSLT
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/document"> <html> <body> <xsl:apply-templates/> <h3>Dynamic title (was not in the XML)</h3> </body> </html> </xsl:template> <xsl:template match="h2 | h3 | h4"> <xsl:element name="{name()}"> ¶<xsl:value-of select="."/> </xsl:element> </xsl:template> </xsl:stylesheet>
问题描述
转换对原始XML中的<h2>、<h3>和<h4>元素生效,但直接在XSLT中输出的动态<h3>元素未被匹配h2 | h3 | h4的模板处理,无法添加前缀¶。
解决方案
直接输出的<h3>是写入结果树的节点,不会触发模板匹配——模板默认只作用于源XML文档的节点或显式指定的节点树。以下两种方法可实现统一转换:
方案一:对动态构造的节点树应用模板
先将动态元素构造为节点变量,再用<xsl:apply-templates>处理该变量内的节点,触发匹配模板:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/document"> <html> <body> <xsl:apply-templates/> <!-- 构造动态节点并应用模板 --> <xsl:variable name="dynamic-heading"> <h3>Dynamic title (was not in the XML)</h3> </xsl:variable> <xsl:apply-templates select="$dynamic-heading/h3"/> </body> </html> </xsl:template> <xsl:template match="h2 | h3 | h4"> <xsl:element name="{name()}"> ¶<xsl:value-of select="."/> </xsl:element> </xsl:template> </xsl:stylesheet>
方案二:抽离转换逻辑为命名模板
把标题的转换逻辑封装成命名模板,原生元素和动态元素统一调用该模板,避免重复代码:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/document"> <html> <body> <xsl:apply-templates/> <!-- 调用命名模板处理动态标题 --> <xsl:call-template name="process-heading"> <xsl:with-param name="heading-name" select="'h3'"/> <xsl:with-param name="heading-text" select="'Dynamic title (was not in the XML)'"/> </xsl:call-template> </body> </html> </xsl:template> <!-- 原生标题元素的模板,转发到命名模板 --> <xsl:template match="h2 | h3 | h4"> <xsl:call-template name="process-heading"> <xsl:with-param name="heading-name" select="name()"/> <xsl:with-param name="heading-text" select="."/> </xsl:call-template> </xsl:template> <!-- 通用标题处理逻辑 --> <xsl:template name="process-heading"> <xsl:param name="heading-name"/> <xsl:param name="heading-text"/> <xsl:element name="{$heading-name}"> ¶<xsl:value-of select="$heading-text"/> </xsl:element> </xsl:template> </xsl:stylesheet>
效果验证
两种方案都能让动态生成的<h3>元素与原生标题元素一致,添加前缀¶,实现统一的转换效果。
内容的提问来源于stack exchange,提问作者fauve
相关产品推荐
相关产品推荐

