如何在一个xml节点上应用多个xsl-templates

时间:2017-08-23 14:17:51

标签: html xml xslt

这是我的问题:

我有带CSS样式的HTML文档。我需要将这些样式移动到正文中的元素中,然后将它们从样式标记中删除。

我做了一个帮助,为每个css样式和值生成xpath,需要放在那里。然后它生成XSL文档并将其应用于HTML。

有时需要将多个xsl-templates应用于同一节点(相同匹配)。只有第一个被应用,其他被忽略。

我如何全部应用它们?

以下是HTML的一个示例:

<html lang="en">
<head>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=utf-8"/>
   <style type="text/css">
      .right-aligned { text-align: right !important; }
      .full-width { width: 100% !important; display: inline-block; }
   </style>
</head>
<body>
   <table class="header">
      <tr>
         <td class="icon">
            <img alt="Minor" src="Picture_SRC" />
         </td>
            <td>
               <div class="secondary full-width right-aligned">Blah: Test</div>
            </td>
         </tr>
      </table>
   </body>
</html>

此HTML需要进行XSL转换:

<xsl:template match="//*[contains(@class,'right-aligned') and @style]">
   <xsl:attribute name="style">
      <xsl:value-of select="concat(., 'text-align: right !important;')"/>
   </xsl:attribute>
</xsl:template>
<xsl:template match="//*[contains(@class,'right-aligned') and not(@style)]">
   <xsl:copy>
      <xsl:attribute name="style">text-align: right !important;</xsl:attribute>
      <xsl:apply-templates select="@*| node()"/>
   </xsl:copy>
</xsl:template>
<xsl:template match="//*[contains(@class,'full-width') and @style]">
   <xsl:attribute name="style">
      <xsl:value-of select="concat(., 'width: 100% !important; display: inline-block;')"/>
    </xsl:attribute>
</xsl:template>
<xsl:template match="//*[contains(@class,'full-width') and not(@style)]">
   <xsl:copy>
      <xsl:attribute name="style">width: 100% !important; display: inline-block;</xsl:attribute>
      <xsl:apply-templates select="@*| node()"/>
   </xsl:copy>
</xsl:template>

重要的是:HTML不是静态的,它会改变......所以我不能制作静态XSL。

1 个答案:

答案 0 :(得分:1)

通过使用mode属性,您可以通过以下方式逐个应用每个模板

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

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

  <xsl:template match="@class">
    <xsl:attribute name="style">
      <xsl:if test="@style">
        <xsl:value-of select="@style" />
        <xsl:text>;</xsl:text>
      </xsl:if>
      <xsl:apply-templates select="." mode="right-aligned" />
    </xsl:attribute>
  </xsl:template>

  <xsl:template match="@style" />

  <xsl:template match="@class" mode="right-aligned">
    <xsl:if test="contains(.,'right-aligned')">
      <xsl:text>text-align: right !important;</xsl:text>
    </xsl:if>
    <xsl:apply-templates select="." mode="full-width" />
  </xsl:template>

  <xsl:template match="@class" mode="full-width">
    <xsl:if test="contains(.,'full-width')">
      <xsl:text>width: 100% !important; display: inline-block;</xsl:text>
    </xsl:if>
  </xsl:template>  
</xsl:stylesheet>

如果您可以使用XSLT 2.0,则可以通过使用优先级而不是模式来简化此操作,并使用xsl:next-match来查找具有较低优先级的下一个匹配模板。

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

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

  <xsl:template match="@class" priority="10">
    <xsl:attribute name="style">
      <xsl:if test="@style">
        <xsl:value-of select="@style" />
        <xsl:text>;</xsl:text>
      </xsl:if>
      <xsl:next-match />
    </xsl:attribute>
  </xsl:template>

  <xsl:template match="@style" />

  <xsl:template match="@class[contains(.,'right-aligned')]" priority="9">
    <xsl:text>text-align: right !important;</xsl:text>
    <xsl:next-match />
  </xsl:template>

  <xsl:template match="@class[contains(.,'full-width')]" priority="8">
    <xsl:text>width: 100% !important; display: inline-block;</xsl:text>
    <xsl:next-match />
   </xsl:template>  

  <xsl:template match="@class" /> <!-- Stop the built-in template applying -->
</xsl:stylesheet>