如何让继承的XSL同时实现格式转换与换行替换?
解决XSL两项功能无法同时生效的问题
问题根源
两个功能互斥,基本是处理顺序冲突或者模板匹配逻辑互相覆盖导致的:要么你先把<2029>/<2028>换成换行,把原本要加格式的文本拆成了多个零散节点,后面的strong/em匹配模板抓不到完整内容;要么先处理了格式替换,把换行标记裹进了标签里,后续替换逻辑识别不出这些标记。
解决思路:分两步链式处理
把两个任务拆成独立的模板,按「先处理格式替换,再处理换行」的顺序执行,确保前一步不破坏后一步的处理条件。
1. 先搞定strong/em格式替换
保留你原来的格式匹配逻辑,但要保证处理时原封不动保留<2029>/<2028>标记——只替换目标文本段,其他内容直接输出。
举个例子(假设你用[strong]/[/strong]标记要加粗的内容):
<!-- 匹配包含加粗标记的文本节点 --> <xsl:template match="text()[contains(., '[strong]')]"> <xsl:call-template name="replace-strong"> <xsl:with-param name="text" select="."/> </xsl:call-template> </xsl:template> <!-- 递归替换所有加粗标记 --> <xsl:template name="replace-strong"> <xsl:param name="text"/> <xsl:choose> <xsl:when test="contains($text, '[strong]') and contains(substring-after($text, '[strong]'), '[/strong]')"> <!-- 输出标记前的内容 --> <xsl:value-of select="substring-before($text, '[strong]')"/> <!-- 用strong标签包裹目标内容 --> <strong> <xsl:value-of select="substring-before(substring-after($text, '[strong]'), '[/strong]')"/> </strong> <!-- 递归处理剩余文本 --> <xsl:call-template name="replace-strong"> <xsl:with-param name="text" select="substring-after(substring-after($text, '[strong]'), '[/strong]')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <!-- 没有标记了,直接输出剩余文本 --> <xsl:value-of select="$text"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- 同理写处理em格式的模板 -->
2. 再处理换行符替换
格式替换完成后,专门处理<2029>和<2028>,把它们换成HTML换行<br/>(如果是纯文本就用 )。这里要给这个模板设较低优先级,确保格式替换先执行。
示例模板:
<!-- 优先级设为-1,确保格式替换模板先触发 --> <xsl:template match="text()" priority="-1"> <xsl:variable name="processed-text"> <xsl:call-template name="replace-newlines"> <xsl:with-param name="text" select="."/> </xsl:call-template> </xsl:variable> <!-- 禁用输出转义,确保<br/>能正常输出 --> <xsl:value-of select="$processed-text" disable-output-escaping="yes"/> </xsl:template> <!-- 递归替换换行标记 --> <xsl:template name="replace-newlines"> <xsl:param name="text"/> <xsl:choose> <xsl:when test="contains($text, '<2029>')"> <xsl:value-of select="substring-before($text, '<2029>')"/> <br/> <xsl:call-template name="replace-newlines"> <xsl:with-param name="text" select="substring-after($text, '<2029>')"/> </xsl:call-template> </xsl:when> <xsl:when test="contains($text, '<2028>')"> <xsl:value-of select="substring-before($text, '<2028>')"/> <br/> <xsl:call-template name="replace-newlines"> <xsl:with-param name="text" select="substring-after($text, '<2028>')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$text"/> </xsl:otherwise> </xsl:choose> </xsl:template>
3. 关键注意点
- 确保格式替换的模板匹配模式比换行替换的更具体(比如匹配包含
[strong]的文本,而换行替换匹配所有文本),或者通过priority属性明确指定执行顺序。 - 如果你的原XSL有默认的文本节点模板,要删掉或者调整优先级,避免它覆盖这两个处理模板。
效果验证
假设源XML是:
<body> <p>[strong]重点内容[/strong]<2029>换行后的内容<2028>[em]强调文本[/em]</p> </body>
修改后的XSL处理后,会输出:
<p><strong>重点内容</strong><br/>换行后的内容<br/><em>强调文本</em></p>
内容的提问来源于stack exchange,提问作者CMarcera
相关产品推荐
相关产品推荐

