Счетчик строки XSLT - это так сложно? - PullRequest
5 голосов
/ 27 мая 2010

Я обманывал каждый раз, когда мне нужно было подсчитать строки в XSLT с помощью JScript, но в этом случае я не могу этого сделать. Я просто хочу записать счетчик строк в выходной файл. Этот базовый пример имеет простое решение:

<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 и т. Д.). Кто-нибудь знает, как я могу вывести позицию в файле (т.е. количество строк)?

Ответы [ 4 ]

6 голосов
/ 27 мая 2010

Хотя совершенно невозможно отметить номера строк для сериализации документа 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.
5 голосов
/ 27 мая 2010

Строка в файле 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 или какой-либо другой язык сценариев, чтобы делать то, что вы хотите.

3 голосов
/ 27 мая 2010

Спасибо за ответы, ребята - да, вы совершенно правы, некоторые внешние функции - единственный способ получить такое поведение в 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()" />
1 голос
/ 27 мая 2010

Как правило, 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...