代码之家  ›  专栏  ›  技术社区  ›  Mr AH

XSLT行计数器-有那么难吗?

  •  5
  • Mr AH  · 技术社区  · 14 年前

    每次需要使用JScript在XSLT中进行行计数时,我都会作弊,但在这种情况下,我不能这样做。我只想在整个输出文件中写出一个行计数器。这个基本示例有一个简单的解决方案:

    <xsl:for-each select="Records/Record">
       <xsl:value-of select="position()"/>
    </xsl:for-each>
    

    输出将是:

    等。。。

    但是如果结构与嵌套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>
    

    在这里,前臂内侧会重置计数器(所以你得到1,1,2,3,2,1,2,3,1,2等等)。是否有人知道如何输出文件中的位置(即行数)?

    4 回复  |  直到 14 年前
        1
  •  5
  •   becquerel    14 年前

    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
  •  6
  •   Dimitre Novatchev    14 年前

    虽然很难为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, '&#xA;')"/>
       <xsl:text>&#xA;</xsl:text>
    
       <xsl:call-template name="numberLines">
        <xsl:with-param name="pLastLineNum"
          select="$pLastLineNum+1"/>
        <xsl:with-param name="pText"
          select="substring-after($pText, '&#xA;')"/>
       </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.
    
        3
  •  3
  •   Mr AH    14 年前

    感谢大家的回答-是的,你完全正确,一些外部函数是在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的参数列表中

    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()" />
    
        4
  •  1
  •   Tomalak    14 年前

    一般来说, position() 是指当前节点相对于当前正在处理的整批节点的数目。

    使用“为每个嵌套”示例,当停止为每个构造嵌套并一次选择所有所需元素时,很容易实现连续编号。

    使用此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