每次我需要通过使用JScript在XSLT中进行行计数时我都会作弊,但在这种情况下我不能这样做。我只是想在整个输出文件中写出一个行计数器。这个基本示例有一个简单的解决方案:
<xsl:for-each select="Records/Record">
<xsl:value-of select="position()"/>
</xsl:for-each>
输出将是:
1
2
3
4
等...
但是如果结构与嵌套的foreach的结构更复杂怎么办:
<xsl:for-each select="Records/Record">
<xsl:value-of select="position()"/>
<xsl:for-each select="Records/Record">
<xsl:value-of select="position()"/>
</xsl:for-each>
</xsl:for-each>
在这里,内部foreach将重置计数器(所以你得到1,1,2,3,2,1,2,3,1,2等)。有谁知道如何输出文件中的位置(即行数)?
答案 0 :(得分:6)
虽然标记XML文档序列化的行号是非常不可能的(因为这个序列化本身是不明确的),但完全有可能,并且 easy
,对常规文本行进行编号。
此转化:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:call-template name="numberLines"/>
</xsl:template>
<xsl:template name="numberLines">
<xsl:param name="pLastLineNum" select="0"/>
<xsl:param name="pText" select="."/>
<xsl:if test="string-length($pText)">
<xsl:value-of select="concat($pLastLineNum+1, ' ')"/>
<xsl:value-of select="substring-before($pText, '
')"/>
<xsl:text>
</xsl:text>
<xsl:call-template name="numberLines">
<xsl:with-param name="pLastLineNum"
select="$pLastLineNum+1"/>
<xsl:with-param name="pText"
select="substring-after($pText, '
')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
应用于此XML文档时:
<t>The biggest airlines are imposing "peak travel surcharges"
this summer. In other words, they're going to raise fees
without admitting they're raising fees: Hey, it's not a $30
price hike. It's a surcharge! This comes on the heels of
checked-baggage fees, blanket fees, extra fees for window
and aisle seats, and "snack packs" priced at exorbitant
markups. Hotels in Las Vegas and elsewhere, meanwhile, are
imposing "resort fees" for the use of facilities (in other
words, raising room rates without admitting they're
raising room rates). The chiseling dishonesty of these
tactics rankles, and every one feels like another nail in
the coffin of travel as something liberating and
pleasurable.
</t>
生成所需的行号:
1 The biggest airlines are imposing "peak travel surcharges"
2 this summer. In other words, they're going to raise fees
3 without admitting they're raising fees: Hey, it's not a $30
4 price hike. It's a surcharge! This comes on the heels of
5 checked-baggage fees, blanket fees, extra fees for window
6 and aisle seats, and "snack packs" priced at exorbitant
7 markups. Hotels in Las Vegas and elsewhere, meanwhile, are
8 imposing "resort fees" for the use of facilities (in other
9 words, raising room rates without admitting they're
10 raising room rates). The chiseling dishonesty of these
11 tactics rankles, and every one feels like another nail in
12 the coffin of travel as something liberating and
13 pleasurable.
答案 1 :(得分:5)
XML文件中的一行与元素实际上并不相同。在你的第一个例子中,你并没有真正计算线 - 而是元素的数量。
XML文件可能如下所示:
<cheeseCollection>
<cheese country="Cyprus">Gbejna</cheese><cheese>Liptauer</cheese><cheese>Anari</cheese>
</cheeseCollection>
或者完全相同的XML文件可能如下所示:
<cheeseCollection>
<cheese
country="Cyprus">Gbejna</cheese>
<cheese>Liptauer</cheese>
<cheese>Anari</cheese>
</cheeseCollection>
XSLT将完全相同 - 它不会真的打扰换行符。
因此很难以您希望的方式使用XSLT显示行号 - 它并不是真正意义上的那种解析。
如果我错了,有人会纠正我,但我会说你需要使用Javascript或其他一些脚本语言来做你想做的事。
答案 2 :(得分:3)
感谢回复人员 - 是的,你完全正确,一些外部函数是在XSLT中获得此行为的唯一方法。对于那些搜索,这是我在.Net 3.5中使用编译变换时的方法:
为您的函数创建一个辅助类
/// <summary>
/// Provides functional support to XSLT
/// </summary>
public class XslHelper
{
/// <summary>
/// Initialise the line counter value to 1
/// </summary>
Int32 counter = 1;
/// <summary>
/// Increment and return the line count
/// </summary>
/// <returns></returns>
public Int32 IncrementCount()
{
return counter++;
}
}
将实例添加到XSLT的args列表
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(XmlReader.Create(s));
XsltArgumentList xslArg = new XsltArgumentList();
XslHelper helper = new XslHelper();
xslArg.AddExtensionObject("urn:helper", helper);
xslt.Transform(xd.CreateReader(), xslArg, writer);
在XSLT中使用它
将它放在样式表声明元素中:
xmlns:helper="urn:helper"
然后像这样使用:
<xsl:value-of select="helper:IncrementCount()" />
答案 3 :(得分:1)
通常,position()
指的是当前节点相对于当前正在处理的整批节点的数量。
使用“嵌套for-each”示例,当您为每个构造停止嵌套时,可以很容易地实现连续编号,并且只需一次选择所有需要的元素。
使用此XML:
<a><b><c/><c/></b><b><c/></b></a>
像这样的循环结构
<xsl:for-each "a/b">
<xsl:value-of select="position()" />
<xsl:for-each "c">
<xsl:value-of select="position()" />
</xsl:for-each>
</xsl:for-each>
将导致
11221
bccbc // referred-to nodes
但你可以这样做:
<xsl:for-each "a/b/c">
<xsl:value-of select="position()" />
</xsl:for-each>
你会得到
123
ccc // referred-to nodes