我有一些像这样的XML:
<story><p><strong>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</strong>Nulla vel mauris metus. Etiam vel tortor vel magna bibendum euismod nec varius turpis. Nullam ullamcorper, nunc vel auctor consectetur, quam felis accumsan eros, lacinia fringilla mauris est vel lectus. Curabitur et tortor eros. Duis sed convallis metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras tempus quam sed enim gravida bibendum. Vestibulum magna ligula, varius in sodales eu, ultricies volutpat sem. Phasellus ante justo, vestibulum eu hendrerit a, posuere vitae est. Integer at pulvinar est.</p><p>Quisque a commodo eros. Integer tempus mi sit amet leo consectetur adipiscing. Nullam sit amet enim metus. Curabitur sollicitudin egestas arcu, at convallis enim iaculis eget. Etiam faucibus, justo sit amet lacinia consectetur, purus nunc rhoncus dui, id malesuada tortor est sed orci. Quisque eget nisi vitae mi facilisis varius. Integer fringilla eros sit amet velit vehicula commodo. </p><br /><span>And some more text here</span>
</story>
我想这样做:
<xsl:copy-of select="substring(story/node(),1,500)"/>
这是问题所在。每当我使用子字符串时,我都会丢失<p>, <strong>, <br />
标记内的<story>
和其他HTML标记。有没有办法在保留内部HTML标签的同时获取故事标签的前500个字符?
谢谢!
答案 0 :(得分:3)
这是XSLT 1.0中的另一种方法,无需使用node-set
扩展名:
<xsl:template match="@*|node()" mode="limit-length">
<xsl:param name="length"/>
<xsl:copy>
<xsl:apply-templates select="@*" mode="limit-length"/>
<xsl:call-template name="copy-nodes">
<xsl:with-param name="nodes" select="node()"/>
<xsl:with-param name="length" select="$length"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" mode="limit-length">
<xsl:param name="length"/>
<xsl:value-of select="substring(., 1, $length)"/>
</xsl:template>
<xsl:template name="copy-nodes">
<xsl:param name="nodes"/>
<xsl:param name="length"/>
<xsl:if test="$length > 0 and $nodes">
<xsl:variable name="head" select="$nodes[1]"/>
<xsl:apply-templates select="$head" mode="limit-length">
<xsl:with-param name="length" select="$length"/>
</xsl:apply-templates>
<xsl:variable name="remaining" select="$length - string-length($head)"/>
<xsl:if test="$remaining > 0 and count($nodes) > 1">
<xsl:call-template name="copy-nodes">
<xsl:with-param name="nodes" select="$nodes[position() > 1]"/>
<xsl:with-param name="length" select="$remaining"/>
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:template>
基本上这是身份模板,将子节点的副本卸载到递归模板,该模板负责保持最大字符串长度,加上文本节点的单独模板,将它们截断为最大长度。
您可以按如下方式为示例输入调用此项:
<xsl:call-template name="copy-nodes">
<xsl:with-param name="nodes" select="story/node()"/>
<xsl:with-param name="length" select="500"/>
</xsl:call-template>
关于在N个字符后第一个休息或段落结束后将故事分成两部分的后续问题,我将继续进行简化假设,即您只想在<p>
之后进行分割。 <br>
元素在<story>
元素下显示为直接子元素(并未嵌套在任意深度)。这使得整个问题变得更加容易。
以下是实现它的一种方法:要获取第一部分的内容,您可以使用一个模板来处理一组兄弟节点,直到超过最大字符串长度并br
或{{遇到1}},然后停止。
p
对于第二部分,您可以创建另一个模板,该模板搜索与前一个模板相同的条件,但直到该点之后才输出任何内容:
<xsl:template match="node()" mode="before-break">
<xsl:param name="length"/>
<xsl:if test="$length > 0 or not(self::br or self::p)">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::node()[1]"
mode="before-break">
<xsl:with-param name="length" select="$length - string-length(.)"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
以下是使用这些模板将故事分成两个 <xsl:template match="node()" mode="after-break">
<xsl:param name="length"/>
<xsl:choose>
<xsl:when test="$length > 0 or not(self::br or self::p)">
<xsl:apply-templates select="following-sibling::node()[1]"
mode="after-break">
<xsl:with-param name="length" select="$length - string-length(.)"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:if test="not(self::br)"> <!-- suppress the <br/> -->
<xsl:copy-of select="."/>
</xsl:if>
<xsl:copy-of select="following-sibling::node()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
的方法。
<div>
答案 1 :(得分:0)
Get N characters introduction text with XSLT 1.0 from XHTML
的问题非常相似这是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">500</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 < 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(.) > 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>
它通过循环遍历节点的子节点,并将前一个兄弟节点的长度计算到该点。请注意,获取前一个兄弟节点长度的代码需要使用节点集函数,该函数是XSLT 1.0的扩展函数。在我的示例中,我使用Microsoft扩展功能。
如果节点不是文本节点,则到该点的字符总长度将是前一个兄弟节点长度的总和,将父节点的前一个兄弟节点的总和(作为一个节点传递)模板的参数)。
将XSLT应用于输入XML时,将输出以下内容:
<story>
<p>
<strong>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</strong>Nulla vel mauris metus. Etiam vel tortor vel magna bibendum euismod nec varius turpis. Nullam ullamcorper, nunc vel auctor consectetur, quam felis accumsan eros, lacinia fringilla mauris est vel lectus. Curabitur et tortor eros. Duis sed convallis metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras tempus quam sed enim gravida bibendum. Vestibulum magna ligula, varius in sodales eu, ultr...
</p>
</story>