Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
193 views
in Technique[技术] by (71.8m points)

html - How to apply more then one xsl-templates on one xml node

here is my problem:

I have HTML Document with CSS Styles. I need to move these styles into the elements in the body and remove them from style tag.

I made helper that makes xpath for each css style and value which needs to be put there. Then it generates XSL documents and applies it to the HTML.

The thing is sometimes there are multiple xsl-templates that needs to be applied to the same Node (same match). And just the first one is getting applied, others are ignored.

How i can apply them all?

Here is one example of the 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>

And there is the XSL Transformations that needed to be done for this HTML:

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

Important thing: the HTML is not static and it changes ... so i can't make static XSL.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is one way you could do it, by use of mode attributes, to apply each template one after another

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

If you could use XSLT 2.0, you could simplify this by use of priorities, instead of modes, and xsl:next-match to find the next matching template with a lower priority.

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...