You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用XSL检查特定节点内容 满足条件时修改MathML转义字符

XSLT转义MathML字符方案

核心错误原因

  1. 语法报错原因:xsl:otherwise 仅能作为 xsl:choose 的直接子元素存在,不能直接放在 xsl:for-each 节点下。
  2. 逻辑缺陷:你编写的匹配根节点/的模板覆盖了初始的身份复制模板,导致原文档结构无法完整输出;同时XPath大小写敏感,你写的select="Text"无法匹配到文本节点,文本节点的正确选择写法是text()。
  3. 实现思路问题:不需要用xsl:for-each手动遍历mtext节点,XSLT的模板匹配机制会自动命中目标节点,配合身份模板可以完整保留原文档所有结构、属性、非目标节点内容。

可直接运行的实现代码

以下代码兼容XSLT 1.0,可直接在C#的XslCompiledTransform中使用,实现三个核心需求:

  • 仅对<mtext>节点内的{、}、[、]字符添加反斜杠转义
  • 完整保留MathML原结构、所有属性、其他节点内容不变
  • 保留&#160;实体不被转换为普通空格
<?xml version='1.0' encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:m="http://www.w3.org/1998/Math/MathML">
    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>

    <!-- 身份模板:复制所有未被特殊匹配的节点、属性 -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>

    <!-- 匹配mtext节点,处理内部文本转义 -->
    <xsl:template match="m:mtext">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:call-template name="multi-replace">
                <xsl:with-param name="text" select="text()"/>
            </xsl:call-template>
        </xsl:copy>
    </xsl:template>

    <!-- 多字符递归替换模板 -->
    <xsl:template name="multi-replace">
        <xsl:param name="text"/>
        <xsl:choose>
            <!-- 优先保留&#160;实体 -->
            <xsl:when test="contains($text, '&#160;')">
                <xsl:value-of select="substring-before($text, '&#160;')"/>
                <xsl:text disable-output-escaping="yes">&amp;#160;</xsl:text>
                <xsl:call-template name="multi-replace">
                    <xsl:with-param name="text" select="substring-after($text, '&#160;')"/>
                </xsl:call-template>
            </xsl:when>
            <!-- 依次转义四个括号字符 -->
            <xsl:when test="contains($text, '{')">
                <xsl:value-of select="substring-before($text, '{')"/>
                <xsl:text>\{</xsl:text>
                <xsl:call-template name="multi-replace">
                    <xsl:with-param name="text" select="substring-after($text, '{')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="contains($text, '}')">
                <xsl:value-of select="substring-before($text, '}')"/>
                <xsl:text>\}</xsl:text>
                <xsl:call-template name="multi-replace">
                    <xsl:with-param name="text" select="substring-after($text, '}')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="contains($text, '[')">
                <xsl:value-of select="substring-before($text, '[')"/>
                <xsl:text>\[</xsl:text>
                <xsl:call-template name="multi-replace">
                    <xsl:with-param name="text" select="substring-after($text, '[')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="contains($text, ']')">
                <xsl:value-of select="substring-before($text, ']')"/>
                <xsl:text>\]</xsl:text>
                <xsl:call-template name="multi-replace">
                    <xsl:with-param name="text" select="substring-after($text, ']')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$text"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

关键说明

  • 代码中声明了MathML的默认命名空间前缀,直接匹配m:mtext比用local-name()='mtext'更严谨,不会误处理其他命名空间下的同名节点。
  • &#160;保留逻辑通过disable-output-escaping实现:XML解析阶段&#160;会被转换为Unicode非断空格字符(U+00A0),输出时手动写回转义实体并禁止输出转义,即可保留原实体格式。
  • 递归替换逻辑在同一个模板内完成所有字符的判断替换,不需要多次嵌套调用单字符替换模板,执行效率更高。如果后续需要新增转义字符,只需要在xsl:choose节点内新增对应的判断分支即可。
  • 你之前尝试用translate()函数失败是符合预期的,该函数仅支持单字符到单字符的映射,无法实现单字符替换为双字符的需求。

内容的提问来源于stack exchange,提问作者nyghtrunner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 20:42:16