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

发布于 2024-10-15 20:48:43 字数 2997 浏览 3 评论 0原文

这是此问题的后续问题。

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

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

这是我当前的 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>

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

提前致谢


更新:

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


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

This is a followup to this question.

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.

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.

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.

An example of the input:

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

gets transformed to:

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

when the desired result is:

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

How can I fix the ambiguous rule match for this?

Thanks in advance


Update:

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?


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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

计㈡愣 2024-10-22 20:48:43

编辑:以防万一真正的问题被隐藏,我简化了样式表:

<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覆盖它)和两个名称模板(解析器/标记器和嵌套内容的生成器)

原始样式表:

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

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

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>

Output:

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

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)

Original 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"
 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)

神魇的王 2024-10-22 20:48:43

这是一个使用 str-split-to-words 模板/函数的 XSLT 1.0 解决方案FXSL

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 exclude-result-prefixes="ext"
>
  <xsl:import href="strSplit-to-Words.xsl"/>
  <xsl:output indent="yes" omit-xml-declaration="yes"/>

  <xsl:param name="pStyleReps">
    <r s="font-style:italic"><em/></r>
    <r s="font-weight:600"><strong/></r>
    <r s="text-decoration:underline"><u/></r>
  </xsl:param>

  <xsl:variable name="vReps" select=
  "document('')/*/xsl:param[@name='pStyleReps']/*"/>

   <xsl:template match="span">
       <xsl:variable name="vrtfStyles">
         <xsl:call-template name="str-split-to-words">
          <xsl:with-param name="pStr" select="@style"/>
          <xsl:with-param name="pDelimiters" select="';'"/>
         </xsl:call-template>
       </xsl:variable>

       <xsl:variable name="vStyles" select=
       "ext:node-set($vrtfStyles)/*"/>

       <xsl:choose>
        <xsl:when test=
         "not($vReps/@s[contains(current()/@style, .)])">
          <xsl:copy-of select="."/>
        </xsl:when>
        <xsl:otherwise>
          <span>
           <xsl:copy-of select="@*"/>
           <xsl:attribute name="style">
             <xsl:for-each select=
              "$vStyles[not(translate(.,' ','')=$vReps/@s)]">
              <xsl:value-of select="."/>
              <xsl:if test="not(position()=last())">;</xsl:if>
             </xsl:for-each>
           </xsl:attribute>

           <xsl:call-template name="styles2markup">
             <xsl:with-param name="pStyles" select=
             "$vReps/@s
                 [contains
                   (translate(current()/@style, ' ', ''),
                    .
                    )
                 ]"/>
           </xsl:call-template>
          </span>
        </xsl:otherwise>
       </xsl:choose>
    </xsl:template>

    <xsl:template name="styles2markup">
     <xsl:param name="pResult" select="text()"/>
     <xsl:param name="pStyles"/>

     <xsl:choose>
     <xsl:when test="not($pStyles)">
      <xsl:copy-of select="$pResult"/>
     </xsl:when>
     <xsl:otherwise>
      <xsl:variable name="vrtfnewResult">
        <xsl:element name="{name($pStyles[1]/../*)}">
         <xsl:copy-of select="$pResult"/>
        </xsl:element>
      </xsl:variable>

      <xsl:call-template name="styles2markup">
       <xsl:with-param name="pStyles" select=
       "$pStyles[position()>1]"/>
       <xsl:with-param name="pResult" select=
       "ext:node-set($vrtfnewResult)/*"/>
      </xsl:call-template>
     </xsl:otherwise>
     </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

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

生成所需的正确结果

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

Here is an XSLT 1.0 solution using the str-split-to-words template/function of FXSL:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 exclude-result-prefixes="ext"
>
  <xsl:import href="strSplit-to-Words.xsl"/>
  <xsl:output indent="yes" omit-xml-declaration="yes"/>

  <xsl:param name="pStyleReps">
    <r s="font-style:italic"><em/></r>
    <r s="font-weight:600"><strong/></r>
    <r s="text-decoration:underline"><u/></r>
  </xsl:param>

  <xsl:variable name="vReps" select=
  "document('')/*/xsl:param[@name='pStyleReps']/*"/>

   <xsl:template match="span">
       <xsl:variable name="vrtfStyles">
         <xsl:call-template name="str-split-to-words">
          <xsl:with-param name="pStr" select="@style"/>
          <xsl:with-param name="pDelimiters" select="';'"/>
         </xsl:call-template>
       </xsl:variable>

       <xsl:variable name="vStyles" select=
       "ext:node-set($vrtfStyles)/*"/>

       <xsl:choose>
        <xsl:when test=
         "not($vReps/@s[contains(current()/@style, .)])">
          <xsl:copy-of select="."/>
        </xsl:when>
        <xsl:otherwise>
          <span>
           <xsl:copy-of select="@*"/>
           <xsl:attribute name="style">
             <xsl:for-each select=
              "$vStyles[not(translate(.,' ','')=$vReps/@s)]">
              <xsl:value-of select="."/>
              <xsl:if test="not(position()=last())">;</xsl:if>
             </xsl:for-each>
           </xsl:attribute>

           <xsl:call-template name="styles2markup">
             <xsl:with-param name="pStyles" select=
             "$vReps/@s
                 [contains
                   (translate(current()/@style, ' ', ''),
                    .
                    )
                 ]"/>
           </xsl:call-template>
          </span>
        </xsl:otherwise>
       </xsl:choose>
    </xsl:template>

    <xsl:template name="styles2markup">
     <xsl:param name="pResult" select="text()"/>
     <xsl:param name="pStyles"/>

     <xsl:choose>
     <xsl:when test="not($pStyles)">
      <xsl:copy-of select="$pResult"/>
     </xsl:when>
     <xsl:otherwise>
      <xsl:variable name="vrtfnewResult">
        <xsl:element name="{name($pStyles[1]/../*)}">
         <xsl:copy-of select="$pResult"/>
        </xsl:element>
      </xsl:variable>

      <xsl:call-template name="styles2markup">
       <xsl:with-param name="pStyles" select=
       "$pStyles[position()>1]"/>
       <xsl:with-param name="pResult" select=
       "ext:node-set($vrtfnewResult)/*"/>
      </xsl:call-template>
     </xsl:otherwise>
     </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the provided XML document:

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

the wanted, correct result is produced:

<span style=" color:#555555">
   <u>
      <strong>some text</strong>
   </u>
</span>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文