代码之家  ›  专栏  ›  技术社区  ›  raspi

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

  •  0
  • raspi  · 技术社区  · 14 年前

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

    • HTML实体感知(   & ),一个实体=一个字符
    • 输入HTML始终有效
    • 输入标记限制为:a、img、p、div、span、b、strong

    输入HTML示例:

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

    <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 回复  |  直到 14 年前
        1
  •  1
  •   Tim C    14 年前

    这是一个起点,尽管它目前不包含任何代码来处理需求“输入标记被限制为:a、img、p、div、span、b、strong”

    如果节点不是文本节点,则到该点的字符总长度将是前面同级节点的长度之和,将父节点前面同级节点的长度之和(作为参数传递给模板)。

    这里是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>
    
        2
  •  0
  •   user357812 user357812    14 年前

    此样式表:

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

    这个输入 4 作为 P最大长度 :

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

    输出:

    <html><p><a href="http://domain.tld">link...</a></p></html>
    
        3
  •  0
  •   raspi    12 年前

    正如许多人所指出的:这会很快变得非常混乱。所以我刚刚在DB中添加了另一个字段,它包含了介绍文本。