根据元素的属性值将元素转换为多个嵌套元素

时间:2017-03-24 17:10:16

标签: xslt xslt-1.0

我有一些包含样式跨度的HTML:

<p><span class="foo">unstyled span</span></p>
<p><span style="font-style: italic;">italic</span></p>
<p><span style="font-weight: bold; font-style: italic;">bold italic</span></p>
<p><span style="text-decoration: underline; font-style: italic; font-weight: bold;">underline italic bold</span></p>

Spans也用于设置字体和背景颜色以及更多内容。基本上我必须用spanem等替换strong标签,尽可能保留一些样式并删除其他所有内容(不需要的样式和类)。对于上述输入,所需的输出为:

<p>unstyled span</p>
<p><em>italic</em></p>
<p><em><strong>bold italic</strong></em></p>
<p><em><strong><span style="text-decoration: underline;">underline italic bold</span></strong></em></p>

凭借我非常有限的XSLT技能,我能够编写以下转换来完成工作,但看起来很难看:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="html" omit-xml-declaration="yes"/>

  <xsl:template match="span">
    <xsl:call-template name="startStyleTests" select="." />
  </xsl:template>

  <xsl:template name="startStyleTests">
    <xsl:call-template name="testItalic" select="." />
  </xsl:template>

  <xsl:template name="testItalic">
    <xsl:choose>
      <xsl:when test="contains(./@style, 'italic')">
        <xsl:element name="em"><xsl:call-template name="testBold" select="." /></xsl:element>
      </xsl:when>
      <xsl:otherwise><xsl:call-template name="testBold" select="." /></xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="testBold">
    <xsl:choose>
      <xsl:when test="contains(./@style, 'bold')">
        <xsl:element name="strong"><xsl:call-template name="testUnderline" select="." /></xsl:element>
      </xsl:when>
      <xsl:otherwise><xsl:call-template name="testUnderline" select="." /></xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="testUnderline">
    <xsl:choose>
      <xsl:when test="contains(./@style, 'underline')">
        <xsl:element name="span">
          <xsl:attribute name="style">text-decoration: underline;</xsl:attribute>
          <xsl:call-template name="endStyleTests" select="." />
        </xsl:element>
      </xsl:when>
      <xsl:otherwise><xsl:call-template name="endStyleTests" select="." /></xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="endStyleTests">
      <xsl:apply-templates />
  </xsl:template>

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

</xsl:transform>

(为了便于阅读,删除了一些&#34; testSomething&#34;模板)

使用XSLT 1.0应该如何实现?

1 个答案:

答案 0 :(得分:0)

你可以做的是创建一个包含&#34;映射的变量&#34;您想要的元素的样式

<xsl:variable name="styles">
   <style match="italic" element="em" />
   <style match="bold" element="strong" />
   <style match="underline" element="span" style="text-decoration: underline;" />
</xsl:variable>

然后,您可以拥有一个模板,而不是每个样式映射都有单独的模板,它们依次递归地检查每个映射。

请注意,在XSLT 1.0中,styles变量实际上包含所谓的&#34;结果树片段&#34;,因此您需要一个扩展函数来将它们作为节点进行处理。

试试这个XSLT

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
               xmlns:exslt="http://exslt.org/common"
               exclude-result-prefixes="exslt">

  <xsl:output method="html" omit-xml-declaration="yes"/>

  <xsl:variable name="styles">
    <style match="italic" element="em" />
    <style match="bold" element="strong" />
    <style match="underline" element="span" style="text-decoration: underline;" />
  </xsl:variable>

  <xsl:template match="span">
    <xsl:call-template name="startStyleTests" /> 
  </xsl:template>

  <xsl:template name="startStyleTests">
    <xsl:param name="styleNumber" select="1" />
    <xsl:variable name="style" select="exslt:node-set($styles)/style[position() = $styleNumber]" />
    <xsl:choose>
      <xsl:when test="not($style)">
          <xsl:call-template name="endStyleTests" />
      </xsl:when>
      <xsl:when test="contains(@style, $style/@match)">
        <xsl:element name="{$style/@element}">
         <xsl:if test="$style/@style">
           <xsl:attribute name="style">
             <xsl:value-of select="$style/@style" />
           </xsl:attribute>
         </xsl:if>
         <xsl:call-template name="startStyleTests">
            <xsl:with-param name="styleNumber" select="$styleNumber + 1" />
         </xsl:call-template>
        </xsl:element>
      </xsl:when>
      <xsl:otherwise>
       <xsl:call-template name="startStyleTests">
          <xsl:with-param name="styleNumber" select="$styleNumber + 1" />
       </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="endStyleTests">
      <xsl:apply-templates />
  </xsl:template>

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

或者,您可以将样式映射放在单独的XML文档中,然后使用document()函数来访问它。这不需要扩展功能。