XSLT中如何对<opt>子树内容去除首尾空格与换行?
问题:XSLT转换中去除标签内容首尾的空格与换行,保留内部格式
XML输入数据
<?xml version="1.0" ?> <input> <record> <name>James Smith</name> <country>United Kingdom</country> <opt> good social skills, <qualification>MSc</qualification>, 10 years of experience </opt> <section>1B</section> </record> <record> <name>Rafael Pérez</name> <country>Spain</country> <section>2A</section> </record> <record> <name>Marie-Claire Legrand</name> <country>France</country> <opt> clear voice, <qualification>MBA</qualification>, 3 years of experience </opt> <section>1B</section> </record> </input>
现有XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" indent="yes" encoding="utf-8"/> <xsl:template match="input"> <xsl:text>------------------------------------------
</xsl:text> <xsl:for-each select="record"> <xsl:apply-templates select="node()[not(self::text()[not(normalize-space())])]"/> <xsl:text>
------------------------------------------
</xsl:text> </xsl:for-each> </xsl:template> <xsl:template match="qualification"> <xsl:choose> <xsl:when test=". = 'MBA'">Master in Business Administration</xsl:when> <xsl:when test=". = 'MSc'">Master in Sciences</xsl:when> <xsl:otherwise><xsl:value-of select="."/></xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="name|country"> <xsl:value-of select="."/> <xsl:text>, </xsl:text> </xsl:template> <xsl:template match="section"> <xsl:text>Section: </xsl:text> <xsl:value-of select="."/> <xsl:text>.</xsl:text> </xsl:template> <xsl:template match="opt"> <xsl:text>(</xsl:text> <xsl:apply-templates/> <xsl:text>), </xsl:text> </xsl:template> </xsl:stylesheet>
当前输出结果
------------------------------------------ James Smith, United Kingdom, ( good social skills, Master in Sciences, 10 years of experience ), Section: 1B. ------------------------------------------ Rafael Pérez, Spain, Section: 2A. ------------------------------------------ Marie-Claire Legrand, France, ( clear voice, Master in Business Administration, 3 years of experience ), Section: 1B. ------------------------------------------
期望输出结果
------------------------------------------ James Smith, United Kingdom, (good social skills, Master in Sciences, 10 years of experience), Section: 1B. ------------------------------------------ Rafael Pérez, Spain, Section: 2A. ------------------------------------------ Marie-Claire Legrand, France, (clear voice, Master in Business Administration, 3 years of experience), Section: 1B. ------------------------------------------
解决方案
问题出在<opt>标签下的首尾文本节点包含多余的换行和空格,我们需要针对性处理这些文本节点,同时保留内部的格式和标签转换逻辑。
修改后的XSLT代码如下(核心修改为<opt>模板及新增的文本节点处理模板):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" indent="yes" encoding="utf-8"/> <xsl:template match="input"> <xsl:text>------------------------------------------
</xsl:text> <xsl:for-each select="record"> <xsl:apply-templates select="node()[not(self::text()[not(normalize-space())])]"/> <xsl:text>
------------------------------------------
</xsl:text> </xsl:for-each> </xsl:template> <xsl:template match="qualification"> <xsl:choose> <xsl:when test=". = 'MBA'">Master in Business Administration</xsl:when> <xsl:when test=". = 'MSc'">Master in Sciences</xsl:when> <xsl:otherwise><xsl:value-of select="."/></xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="name|country"> <xsl:value-of select="."/> <xsl:text>, </xsl:text> </xsl:template> <xsl:template match="section"> <xsl:text>Section: </xsl:text> <xsl:value-of select="."/> <xsl:text>.</xsl:text> </xsl:template> <!-- 修改opt模板,分节点处理首尾空白 --> <xsl:template match="opt"> <xsl:text>(</xsl:text> <!-- 处理第一个子节点,去除前导空白 --> <xsl:apply-templates select="node()[1]" mode="trim-start"/> <!-- 处理中间节点,保留原样 --> <xsl:apply-templates select="node()[position() > 1 and position() < last()]"/> <!-- 处理最后一个子节点,去除尾随空白 --> <xsl:apply-templates select="node()[last()]" mode="trim-end"/> <xsl:text>), </xsl:text> </xsl:template> <!-- 去除文本节点的前导空白 --> <xsl:template match="text()" mode="trim-start"> <xsl:value-of select="substring(., string-length(substring-before(., normalize-space(.))) + 1)"/> </xsl:template> <!-- 去除文本节点的尾随空白 --> <xsl:template match="text()" mode="trim-end"> <xsl:value-of select="substring(., 1, string-length(.) - string-length(substring-after(normalize-space(.), normalize-space(.))))"/> </xsl:template> <!-- 非文本节点在trim模式下直接应用原模板 --> <xsl:template match="*" mode="trim-start"> <xsl:apply-templates select="."/> </xsl:template> <xsl:template match="*" mode="trim-end"> <xsl:apply-templates select="."/> </xsl:template> </xsl:stylesheet>
核心逻辑说明
<opt>模板拆分处理:将子节点分为首节点、中间节点、尾节点分别处理,确保首尾节点的空白被清理,中间节点保留原有格式。- trim-start模式:针对第一个文本节点,通过
substring截取从第一个非空白字符开始的内容,去除前导的换行和空格。 - trim-end模式:针对最后一个文本节点,截取到最后一个非空白字符结束的内容,去除尾随的换行和空格。
- 非文本节点兼容:对于
<qualification>这类标签节点,在trim模式下直接调用原模板完成替换,不影响原有逻辑。
内容的提问来源于stack exchange,提问作者Pierre François
相关产品推荐
相关产品推荐

