Как посчитать выходные строки с помощью xslt? - PullRequest
2 голосов
/ 23 августа 2010

Я выводю текст с помощью XSLT.Мне нужно посчитать количество строк каждого раздела и записать его в мой выходной файл.Как это можно сделать?

Мой вывод выглядит так:

HDR+aaa:bbb'
AAA+78901234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+112211'
DDD+121122'
XXX+number_of_records+78901234567890'
AAA+1234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+1212:2121'
BBB+123+String'
BBB+122+String'
CCC+String'
XXX+number_of_records+1234567890'

Число_of_records должно содержать количество строк от AAA до XXX, включая обе строки.В первом разделе количество строк должно быть 6, а во втором сообщении должно быть 8. Первая и последняя строки каждого раздела будут иметь один и тот же уникальный идентификационный номер.

Количество строк не можетбыть посчитанным из источника, поскольку внутри XSLT так много обработки.

Ответы [ 3 ]

2 голосов
/ 23 августа 2010

Концептуально простым способом сделать это было бы использование процесса второго этапа. Возьмите выходные данные вашего первоначального преобразования (то, что вы опубликовали) и пропустите его через шаблон (или таблицу стилей, например @ Alejandro's), который разбирает его на строки и группирует строки, начиная с AAA ... и заканчивая XXX. См. Преобразование с повышением частоты с использованием XSLT 2.0 для очень ясного и практического руководства по этому вопросу с использованием tokenize(), xsl:analyze-string и xsl:for-each-group. Затем посчитайте строки в каждой группе и заново выведите каждую строку, вставьте счетчик строк в запись XXX.

Но это неэффективно и несколько подвержено ошибкам, так как вы будете анализировать начальный вывод. Зачем анализировать сериализацию информации, которая уже была у таблицы стилей внутри? Вы можете избежать неэффективности, изменив исходный вывод на XML, что-то вроде

<hdr>
  <section id="78901234567890">
    <!-- It sounds like AAA's ID actually applies to the section? -->
    <AAA String1="..." String2="..."/>
    <BBB .../>
    <!-- no need to include XXX at this stage AFAICT -->
  </section>
  <section id="1234567890">
    ...
  </section>
</hdr>

Тогда шаблон второго этапа (или отдельная таблица стилей) мог бы принять этот XML-код в качестве входных данных и очень легко сериализовать его, как вы это делали выше, считая строки по ходу. В XSLT 1.0 вам придется использовать отдельную таблицу стилей для обработки выходного XML или использовать функцию расширения node-set () . (Но даже с отдельным процессором таблиц стилей вы все равно можете избежать затрат на повторный анализ промежуточного XML, если вы можете объединить два процессора таблиц стилей вместе, используя SAX.) В XSLT 2.0 вы можете обрабатывать вывод XML одного шаблона с помощью другой шаблон, без ограничений.

1 голос
/ 23 августа 2010

Просто для удовольствия, пока вы не опубликуете образец ввода и таблицу стилей для построения этого текстового вывода, эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:template match="result" name="result">
        <xsl:param name="pString" select="."/>
        <xsl:variable name="vAfter" select="substring-after($pString, 'AAA+')"/>
        <xsl:choose>
            <xsl:when test="$vAfter!=''">
                <xsl:variable name="vId" 
                        select="substring-before($vAfter, '+')"/>
                <xsl:variable name="vEnd" 
                  select='concat("XXX+number_of_records+",$vId,"&apos;&#xA;")'/>
                <xsl:variable name="vInto" 
                        select="substring-before($vAfter,$vEnd)"/>
                <xsl:value-of 
                        select='concat(substring-before($pString,"AAA+"),
                             "AAA+",
                             $vInto,
                             "XXX+",
                             string-length(translate($vInto,
                                                     translate($vInto,
                                                               "&#xA;",
                                                               ""),
                                                     "")) + 1,
                             "+",$vId,"&apos;&#xA;")'/>
                <xsl:call-template name="result">
                    <xsl:with-param name="pString" 
                        select="substring-after($vAfter,$vEnd)"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$pString"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

С этим входом:

<result>
HDR+aaa:bbb'
AAA+78901234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+112211'
DDD+121122'
XXX+number_of_records+78901234567890'
AAA+1234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+1212:2121'
BBB+123+String'
BBB+122+String'
CCC+String'
XXX+number_of_records+1234567890'
</result>

Выход:

HDR+aaa:bbb'
AAA+78901234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+112211'
DDD+121122'
XXX+6+78901234567890'
AAA+1234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+1212:2121'
BBB+123+String'
BBB+122+String'
CCC+String'
XXX+8+1234567890'
0 голосов
/ 26 августа 2010

Мое решение: я создал функцию расширения, которая увеличивает number_of_records на единицу каждый раз, когда я ее вызываю. Я использую xsl: comment для подавления вывода, пока мне действительно не нужно вывести число. Я сбрасываю number_of_records после каждой XXX + -линии.

Выполнение этого в два этапа могло бы вызвать слишком много хлопот.

...