如何修改XSL-FO代码以适配任意@*标记组合?
问题:适配任意@*标记的XSL-FO文本转换
此前我提问《Convert text string to xml tagging using xsl pt.2》并获得解决方案,据此编写了XSL-FO代码。需求是将含@c、@v标记的XML文本(如<p>The @c cmdname is a utility and @v varname is an option.</p>)转换为对应格式:cmdname使用等宽字体,varname使用斜体。但当前代码仅@c标记生效,且无法直接使用<i>等XML标签。
现有XSL-FO代码如下:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:template match="text()[contains(., '@c')]"> <xsl:analyze-string select="." regex="@c\s+([!-~]+)"> <xsl:matching-substring> <fo:inline font-family="RobotoMono-Regular"> <xsl:value-of select="regex-group(1)"/> </fo:inline> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:value-of select="."/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:template> <xsl:template match="text()[contains(., '@v')]"> <xsl:analyze-string select="." regex="@v\s+([!-~]+)"> <xsl:matching-substring> <fo:inline font-family="Roboto" font-style="italic"> <xsl:value-of select="regex-group(1)"/> </fo:inline> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:value-of select="."/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:template> </xsl:stylesheet>
解决方案
问题根源
当前两个模板是互斥的:一个文本节点只会匹配第一个符合条件的模板(比如同时包含@c和@v的文本,只会触发@c的模板,@v的标记不会被处理)。要适配任意@*标记,需要合并处理逻辑,用单一正则匹配所有@开头的标记,再根据标记类型应用对应样式。
修改后的代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="2.0"> <!-- 匹配所有文本节点,统一处理所有@*标记 --> <xsl:template match="text()"> <xsl:analyze-string select="." regex="@([cv])\s+([!-~]+)"> <xsl:matching-substring> <!-- 根据捕获的标记类型选择对应FO样式 --> <xsl:choose> <!-- @c标记:等宽字体 --> <xsl:when test="regex-group(1) = 'c'"> <fo:inline font-family="RobotoMono-Regular"> <xsl:value-of select="regex-group(2)"/> </fo:inline> </xsl:when> <!-- @v标记:斜体 --> <xsl:when test="regex-group(1) = 'v'"> <fo:inline font-family="Roboto" font-style="italic"> <xsl:value-of select="regex-group(2)"/> </fo:inline> </xsl:when> <!-- 可扩展:新增其他@*标记的样式分支 --> <!-- <xsl:when test="regex-group(1) = 'b'"> <fo:inline font-weight="bold"> <xsl:value-of select="regex-group(2)"/> </fo:inline> </xsl:when> --> </xsl:choose> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:value-of select="."/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:template> </xsl:stylesheet>
关键说明
- 合并模板:用单个模板匹配所有文本节点,避免互斥问题,确保所有@*标记都能被处理
- 通用正则:
@([cv])\s+([!-~]+)捕获两部分内容:([cv])是标记类型(可扩展为([cvb])等),([!-~]+)是标记后的目标文本 - 动态样式:通过
xsl:choose根据标记类型切换FO样式,后续新增标记只需添加对应的xsl:when分支 - 命名空间修复:补充了FO的命名空间声明(
xmlns:fo="http://www.w3.org/1999/XSL/Format"),否则<fo:inline>标签无法生效
内容的提问来源于stack exchange,提问作者Amy Higgins
相关产品推荐
相关产品推荐

