通过 XSLT 替换 XHTML 中的 style= 属性时的模糊规则匹配 [英] Ambiguous rule match in replacing style= attributes in XHTML via XSLT

查看:27
本文介绍了通过 XSLT 替换 XHTML 中的 style= 属性时的模糊规则匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是这个问题的后续.

我在一个文档中有几个 标签,有几个分号分隔的样式属性.现在我有 3 个特定的样式属性,我正在寻找将其转换为标签.只要 style 属性只包含三个 style 属性之一,在上面的例子中一切都很好.如果一个跨度有更多,我会得到一个不明确的规则匹配.

I have several <span> tags in a document with several semicolon separated style attributes. Right now I have 3 specific style attributes I'm looking for to translate into tags. All works well in the example above as long as the style attribute only contains one of the three style attributes. If a span has more, I get an ambiguous rule match.

我正在寻找的三个样式属性是 font-style:italicfont-weight:600text-decoration:underlinecode> 应该从样式属性中删除并转换为 ,分别.

The three style attributes I'm looking for are font-style:italic, font-weight:600, and text-decoration:underline which should be removed from the style attribute and transformed into <em>, <strong>, and <u>, respectively.

这是我当前的 XSLT:

Here's my current 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>

对于包含多个所列属性的某些元素,哪些会生成模糊规则警告无法正常工作.

Which will generate the ambiguous rule warning doesn't work correctly on some elements that contain more than one of the listed attributes.

输入示例:

<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>

我该如何修复这个不明确的规则匹配?

How can I fix the ambiguous rule match for this?

提前致谢

更新:

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

If i set priorty on each of the templates to descending values and run the XSLT again on the output of the first XSLT run, everything works as expected. There has to be an easier way than running it through the transformation twice. Any ideas?

正如 Alejandro 和 Tomalak 所建议的,将 style 属性替换为 CSS 类的 class 属性也是一种选择.

As Alejandro and Tomalak suggested, replacing the style attributes with a class attribute for CSS classes is an option, too.

推荐答案

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

EDIT: Just in case real problem gets hide, I have simplified the stylesheet:

<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>

输出:

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

注意:使用空间规范化更简单的解析以匹配存在比较中的属性.生成没有优化的内容(选择不匹配,选择匹配).输出嵌套元素的有状态"或堆叠"命名模板.无论哪种方式,都有两个规则(identity 和 span@style 覆盖它)和两个名称模板(解析器/标记器和嵌套内容的生成器)

Note: Simpler parsing with space normalization to match properties in an existencial comparison. Generating content without optimization (selecting no match, selecting match). "Stateful" or "stackful" named template for output nested elements. Either way there are two rules (identity and span with @style overwriting it) and two names templates (parser/tokenizer and generator of nested content)

原始样式表:

<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: Recursion paradise. Nested tokenizer for parsing style properties. "Stateful" template for nested content (and performance matching properties, by the way)

这篇关于通过 XSLT 替换 XHTML 中的 style= 属性时的模糊规则匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆