通过 XSLT 替换 XHTML 中的 style= 属性时出现不明确的规则匹配

2023-12-08

这是后续这个问题.

我有一些<span>文档中的标签具有多个分号分隔的样式属性。现在我有 3 个特定的样式属性,我正在寻找将其转换为标签。只要样式属性仅包含三个样式属性之一,在上面的示例中一切都可以正常工作。如果一个跨度有更多,我会得到一个不明确的规则匹配。

我正在寻找的三个样式属性是font-style:italic, font-weight:600, and text-decoration:underline应该从 style 属性中删除并转换为<em>, <strong>, and <u>, 分别。

这是我当前的 XSLT:

<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="span[
    contains(translate(@style, ' ', ''), 'font-style:italic')
    ]">
    <xsl:copy>
       <xsl:attribute name="style">
            <xsl:value-of select="substring-before(@style, ' font-style')"/>
            <xsl:value-of select="substring-after(@style, 'italic;')"/>
        </xsl:attribute>
        <em>
            <xsl:apply-templates select="node()"/>
        </em>
    </xsl:copy>
</xsl:template>
<xsl:template match="span[
    contains(translate(@style, ' ', ''), 'font-weight:600')
    ]">
    <xsl:copy>
        <xsl:attribute name="style">
            <xsl:value-of select="substring-before(@style, ' font-weight')"/>
            <xsl:value-of select="substring-after(@style, '600;')"/>
        </xsl:attribute>
        <strong>
            <xsl:apply-templates select="node()"/>
        </strong>
    </xsl:copy>
</xsl:template>

<xsl:template match="span[ 
    contains(translate(@style, ' ', ''), 'text-decoration:underline')
    ]">
    <xsl:copy>
        <xsl:attribute name="style">
            <xsl:value-of select="substring-before(@style, ' text-decoration')"/>
            <xsl:value-of select="substring-after(@style, 'underline;')"/>
        </xsl:attribute>
        <u>
            <xsl:apply-templates select="node()"/>
        </u>
    </xsl:copy>
</xsl:template>

这将生成不明确的规则警告,该警告在包含多个列出的属性的某些元素上无法正常工作。

输入示例:

<span style=" text-decoration: underline; font-weight:600; color:#555555">some text</span>

转变为:

<span style=" font-weight:600; color:#555555"><u>some text</u></span>

当期望的结果是:

<span style="color:#555555"><b><u>some text</u></b></span>

我怎样才能解决这个不明确的规则匹配?

提前致谢


Update:

如果我设置priorty将每个模板的值降序,并在第一次 XSLT 运行的输出上再次运行 XSLT,一切都按预期进行。必须有一种比运行两次转换更简单的方法。有任何想法吗?


正如亚历杭德罗和托马拉克建议的那样,替换style属性与classCSS 类的属性也是一个选项。


EDIT:为了防止真正的问题被隐藏,我简化了样式表:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 xmlns:s="styles"
 exclude-result-prefixes="s msxsl">
    <s:s prop="font-style:italic" name="em"/>
    <s:s prop="font-weight:600" name="strong"/>
    <s:s prop="text-decoration:underline" name="u"/>
    <xsl:variable name="vStyles" select="document('')/*/s:s"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="span[@style]">
        <xsl:variable name="vrtfProp">
            <xsl:call-template name="parser"/>
        </xsl:variable>
        <xsl:variable name="vProp"
                      select="msxsl:node-set($vrtfProp)/*"/>
        <xsl:copy>
            <xsl:apply-templates select="@*[name()!='style']"/>
            <xsl:attribute name="style">
                <xsl:for-each select="$vProp[not(.=$vStyles/@prop)]">
                    <xsl:value-of select="concat(.,';')"/>
                </xsl:for-each>
            </xsl:attribute>
            <xsl:call-template name="generate">
                <xsl:with-param
                     name="pElements"
                     select="$vStyles[@prop=$vProp]/@name"/>
            </xsl:call-template>
        </xsl:copy>
    </xsl:template>
    <xsl:template name="generate">
        <xsl:param name="pElements" select="/.."/>
        <xsl:choose>
            <xsl:when test="$pElements">
                <xsl:element name="{$pElements[1]}">
                    <xsl:call-template name="generate">
                        <xsl:with-param
                             name="pElements"
                             select="$pElements[position()>1]"/>
                    </xsl:call-template>
                </xsl:element>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template name="parser">
        <xsl:param name="pString" select="concat(@style,';')"/>
        <xsl:if test="contains($pString,';')">
            <xsl:variable
                 name="vProp"
                 select="substring-before($pString,';')"/>
            <prop>
                <xsl:value-of
                     select="concat(
                                normalize-space(
                                   substring-before($vProp,':')
                                ),
                                ':',
                                normalize-space(
                                   substring-after($vProp,':')
                                )
                             )"/>
            </prop>
            <xsl:call-template name="parser">
                <xsl:with-param
                     name="pString"
                     select="substring-after($pString,';')"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Output:

<span style="color:#555555;"><strong><u>some text</u></strong></span>

Note:通过空间标准化进行更简单的解析,以匹配存在比较中的属性。生成未经优化的内容(选择不匹配、选择匹配)。用于输出的“有状态”或“堆栈”命名模板嵌套元素。无论哪种方式,都有两个规则(身份和span with @style覆盖它)和两个名称模板(解析器/标记器和嵌套内容生成器)

原始样式表:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 xmlns:s="styles"
 xmlns:t="tokenizer"
 exclude-result-prefixes="s t msxsl">
    <s:s r="font-style" v="italic" e="em"/>
    <s:s r="font-weight" v="600" e="strong"/>
    <s:s r="text-decoration" v="underline" e="u"/>
    <t:t s=";" n="p"/>
    <t:t s=":" n="t"/>
    <xsl:variable name="vStyles" select="document('')/*/s:s"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="span[@style]">
        <xsl:variable name="vrtfStyles">
            <xsl:call-template name="tokenizer"/>
        </xsl:variable>
        <xsl:copy>
            <xsl:apply-templates select="@*[name()!='style']"/>
            <xsl:call-template name="generate">
                <xsl:with-param name="pStyles"
                                select="msxsl:node-set($vrtfStyles)/*"/>
            </xsl:call-template>
        </xsl:copy>
    </xsl:template>
    <xsl:template name="generate">
        <xsl:param name="pStyles" select="/.."/>
        <xsl:param name="pAttributes" select="/.."/>
        <xsl:param name="pElements" select="/.."/>
        <xsl:choose>
            <xsl:when test="$pStyles">
                <xsl:variable name="vMatch"
                              select="$vStyles[@r=$pStyles[1]/t[1]]
                                              [@v=$pStyles[1]/t[2]]"/>
                <xsl:call-template name="generate">
                    <xsl:with-param name="pStyles"
                                    select="$pStyles[position()>1]"/>
                    <xsl:with-param name="pAttributes"
                                    select="$pAttributes|
                                            $pStyles[1][not($vMatch)]"/>
                    <xsl:with-param name="pElements"
                                    select="$pElements|$vMatch"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="$pAttributes">
                <xsl:attribute name="style">
                    <xsl:for-each select="$pAttributes">
                        <xsl:value-of select="concat(t[1],':',t[2],';')"/>
                    </xsl:for-each>
                </xsl:attribute>
                <xsl:call-template name="generate">
                    <xsl:with-param name="pElements" select="$pElements"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="$pElements">
                <xsl:element name="{$pElements[1]/@e}">
                    <xsl:call-template name="generate">
                        <xsl:with-param name="pElements"
                                        select="$pElements[position()>1]"/>
                    </xsl:call-template>
                </xsl:element>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template name="tokenizer">
        <xsl:param name="pTokenizer" select="document('')/*/t:t"/>
        <xsl:param name="pString" select="@style"/>
        <xsl:choose>
            <xsl:when test="not($pTokenizer)">
                <xsl:value-of select="normalize-space($pString)"/>
            </xsl:when>
            <xsl:when test="contains($pString,$pTokenizer[1]/@s)">
                <xsl:call-template name="tokenizer">
                    <xsl:with-param name="pTokenizer" select="$pTokenizer"/>
                    <xsl:with-param name="pString"
                                    select="substring-before(
                                               $pString,
                                               $pTokenizer[1]/@s
                                            )"/>
                </xsl:call-template>
                <xsl:call-template name="tokenizer">
                    <xsl:with-param name="pTokenizer" select="$pTokenizer"/>
                    <xsl:with-param name="pString"
                                    select="substring-after(
                                               $pString,
                                               $pTokenizer[1]/@s
                                            )"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:element name="{$pTokenizer[1]/@n}">
                    <xsl:call-template name="tokenizer">
                        <xsl:with-param name="pTokenizer"
                                        select="$pTokenizer[position()>1]"/>
                        <xsl:with-param name="pString" select="$pString"/>
                    </xsl:call-template>
                </xsl:element>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Note:递归天堂。用于解析样式属性的嵌套标记器。嵌套内容的“有状态”模板(顺便说一句,还有性能匹配属性)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过 XSLT 替换 XHTML 中的 style= 属性时出现不明确的规则匹配 的相关文章

随机推荐