使用XHTML中的XSLT 1.0获取N个字符简介文本

时间:2010-10-30 12:10:32

标签: xslt xhtml

如何从XHTML获取XSLT 1.0的前n个字符?我正在尝试为新闻创建介绍文本。

  • 一切都是UTF-8
  • HTML实体感知(  &),一个实体=一个字符
  • 支持HTML标记(添加缺少的结束标记)
  • 输入HTML始终有效
  • 如果输入文本超过n个字符,请将“...”添加到结束输出
  • 输入标签仅限于:a,img,p,div,span,b,strong

示例输入HTML:

<img src="image.jpg" alt="">text <a href="http://domain.tld">link here</a>

包含9个字符的示例输出:

<img src="image.jpg" alt="">text <a href="http://domain.tld">link...</a>

示例输入HTML:

<p><a href="http://domain.tld">link here</a> text</p>

包含4个字符的示例输出:

<p><a href="http://domain.tld">link...</a></p>

3 个答案:

答案 0 :(得分:1)

这是一个起点,虽然它目前不包含任何处理要求的代码“输入标签仅限于:a,img,p,div,span,b,strong”

它通过循环遍历节点的子节点,并将前一个兄弟节点的长度计算到该点。请注意,获取前一个兄弟节点长度的代码需要使用节点集函数,该函数是XSLT 1.0的扩展函数。在我的示例中,我使用Microsoft扩展功能。

如果节点不是文本节点,则到该点的字符总长度将是前一个兄弟节点长度的总和,将父节点的前一个兄弟节点的总和(作为一个节点传递)模板的参数)。

这是XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
   <xsl:param name="MAXCHARS">9</xsl:param>

   <xsl:template match="/body">
      <xsl:apply-templates select="child::node()"/>
   </xsl:template>

   <xsl:template match="node()">
      <xsl:param name="LengthToParent">0</xsl:param>

      <!-- Get length of previous siblings -->
      <xsl:variable name="previousSizes">
         <xsl:for-each select="preceding-sibling::node()">
            <length>
               <xsl:value-of select="string-length(.)"/>
            </length>
         </xsl:for-each>
      </xsl:variable>
      <xsl:variable name="LengthToNode" select="sum(msxsl:node-set($previousSizes)/length)"/>

      <!-- Total amount of characters processed so far -->
      <xsl:variable name="LengthSoFar" select="$LengthToNode + number($LengthToParent)"/>

      <!-- Check limit is not exceeded -->
      <xsl:if test="$LengthSoFar &lt; number($MAXCHARS)">
         <xsl:choose>
            <xsl:when test="self::text()">
               <!-- Output text nonde with ... if required -->
               <xsl:value-of select="substring(., 1, number($MAXCHARS) - $LengthSoFar)"/>
               <xsl:if test="string-length(.) &gt; number($MAXCHARS) - $LengthSoFar">...</xsl:if>
            </xsl:when>
            <xsl:otherwise>
               <!-- Output copy of node and recursively call template on its children -->
               <xsl:copy>
                  <xsl:copy-of select="@*"/>
                  <xsl:apply-templates select="child::node()">
                     <xsl:with-param name="LengthToParent" select="$LengthSoFar"/>
                  </xsl:apply-templates>
               </xsl:copy>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:if>
   </xsl:template>

</xsl:stylesheet>

应用于此输入时

<body> 
   <img src="image.jpg" alt="" />text <a href="http://domain.tld">link here</a>
</body>

输出结果为:

<body> 
   <img src="image.jpg" alt="" />text <a href="http://domain.tld">link...</a>
</body>

应用于此输入(并在XSLT中将参数更改为4)

<p><a href="http://domain.tld">link here</a> text</p>

输出结果为:

<p><a href="http://domain.tld">link...</a></p>

答案 1 :(得分:0)

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="pMaxLength" select="4"/>
    <xsl:template match="node()">
        <xsl:param name="pPrecedingLength" select="0"/>
        <xsl:variable name="vContent">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:apply-templates select="node()[1]">
                    <xsl:with-param name="pPrecedingLength"
                                    select="$pPrecedingLength"/>
                </xsl:apply-templates>
            </xsl:copy>
        </xsl:variable>
        <xsl:variable name="vLength"
                      select="$pPrecedingLength + string-length($vContent)"/>
        <xsl:if test="$pMaxLength + 3 >= $vLength and
                      (string-length($vContent) or not(node()))">
            <xsl:copy-of select="$vContent"/>
            <xsl:apply-templates select="following-sibling::node()[1]">
                <xsl:with-param name="pPrecedingLength" select="$vLength"/>
            </xsl:apply-templates>
        </xsl:if>
    </xsl:template>
    <xsl:template match="text()" priority="1">
        <xsl:param name="pPrecedingLength" select="0"/>
        <xsl:variable name="vOutput"
                      select="substring(.,1,$pMaxLength - $pPrecedingLength)"/>
        <xsl:variable name="vSumLength"
                      select="$pPrecedingLength + string-length($vOutput)"/>
        <xsl:value-of select="concat($vOutput,
                                     substring('...',
                                               1 div ($pMaxLength
                                                            = $vSumLength)))"/>
        <xsl:apply-templates select="following-sibling::node()[1]">
            <xsl:with-param name="pPrecedingLength"
                            select="$vSumLength"/>
        </xsl:apply-templates>
    </xsl:template>
</xsl:stylesheet>

使用此输入并将9设为pMaxLength

<html><img src="image.jpg" alt=""/>text <a href="http://domain.tld">link here</a></html>

输出:

<html><img src="image.jpg" alt="">text <a href="http://domain.tld">link...</a></html>

此输入4pMaxLength

<html><p><a href="http://domain.tld">link here</a> text</p></html>

输出:

<html><p><a href="http://domain.tld">link...</a></p></html>

答案 2 :(得分:0)

正如许多人所指出的那样:非常快速地变得非常混乱。所以我刚刚向DB添加了另一个字段,其中包含介绍文本。