这是this question的后续内容。
我在文档中有几个<span>
标记,其中包含多个以分号分隔的样式属性。现在我有3个特定的样式属性,我正在寻找转换成标签。只要style属性只包含三个样式属性中的一个,所有这些在上面的示例中都很有效。如果跨度更大,我会得到一个模糊的规则匹配。
我正在寻找的三个样式属性是font-style:italic
,font-weight:600
和text-decoration:underline
,它们应从样式属性中删除并转换为<em>
,{{分别为1}}和<strong>
。
这是我目前的XSLT:
<u>
哪些会生成模糊规则警告,但在包含多个列出属性的某些元素上无法正常工作。
输入的一个例子:
<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>
设置为降序值并在第一个XSLT运行的输出上再次运行XSLT,那么一切都按预期工作。必须有一种比通过转换运行两次更简单的方法。有什么想法吗?
正如Alejandro和Tomalak所建议的那样,用CSS类的priorty
属性替换style
属性也是一种选择。
答案 0 :(得分:2)
编辑:为了防止真正的问题被隐藏,我简化了样式表:
<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>
注意:使用空间规范化进行更简单的解析,以匹配存在性比较中的属性。生成内容而不进行优化(选择不匹配,选择匹配)。输出嵌套元素的“有状态”或“堆叠”命名模板。无论哪种方式,有两个规则(标识和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>
注意:递归天堂。嵌套的标记生成器,用于解析样式属性。嵌套内容的“有状态”模板(顺便说一下,性能匹配属性)
答案 1 :(得分:1)
以下是使用FXSL 的str-split-to-words
模板/函数的XSLT 1.0解决方案:
<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>