Аккумулятор не применим к текущему документу с Saxon PE 9-9-1-5 Java

У меня есть входной XML:

<?xml version='1.0' encoding='UTF-8'?>
<MessageFormat name='TransportEvent' version='2.02'>
    <StructFormat name='TransportEventHeader' >
        <TagField type='String' value='H0 '/>
        <FieldFormat name='NotificationTriggeringOU' length='10'/>
        <FieldFormat name='NotificationTriggeringIT' length='8'/>
        <FieldFormat name='NotificationReference' length='1'/>
        <FieldFormat name='NotificationCode' length='3'/>
        <FieldFormat name='NotificationType' length='8'/>
        <FieldFormat name='NotificationStatus' length='1'/>
        <FieldFormat name='NotificationTripType' length='1'/>
        <FieldFormat name='ProducingRailwayUndertaking' length='4'/>
        <FieldFormat name='ExternalPartner' length='35'/>
        <FieldFormat name='ActualNumberOfWagons' length='3' />
        <FieldFormat name='ProcessingTime' length='26'/>
        <StructFormat name='NotificationFunctionalClassification'>
            <FieldFormat name='OrderRelevant' length='1'/>
            <FieldFormat name='TimetableRelevant' length='1'/>
            <FieldFormat name='CapacityRelevant' length='1'/>
            <FieldFormat name='IntermodalRelevant' length='1'/>
            <FieldFormat name='XrailRelevant' length='1'/>
            <FieldFormat name='NotificationLocationRelevant' length='1'/>
        </StructFormat>
        <FieldFormat name='Reserve' length='1'/>
    </StructFormat>
    <StructFormat name='NotificationLocation' >
        <TagField type='String' value='M1 '/>
        <StructFormat name='CurrentLocation'>
            <FieldFormat name='CurrentLocationRL100' length='5'/>
            <FieldFormat name='CurrentLocationLocationType' length='1'/>
            <FieldFormat name='CurrentUICRailAuthorityNumber' length='6'/>
            <FieldFormat name='CurrentNetworkLocationNumber' length='6'/>
            <FieldFormat name='CurrentLocationSatelliteNumber' length='2'/>
            <FieldFormat name='CurrentFreightCarLocationNumber' length='4'/>
        </StructFormat>
        <StructFormat name='NextLocation'>
            <FieldFormat name='NextLocationRL100' length='5'/>
            <FieldFormat name='NextLocationLocationType' length='1'/>
            <FieldFormat name='NextUICRailAuthorityNumber' length='6'/>
            <FieldFormat name='NextNetworkLocationNumber' length='6'/>
            <FieldFormat name='NextLocationSatelliteNumber' length='2'/>
            <FieldFormat name='NextFreightCarLocationNumber' length='4'/>
        </StructFormat>
    </StructFormat>
    <StructFormat name='NotificationTime' >
        <TagField type='String' value='M2 '/>
        <FieldFormat name='ActualTime' length='18'/>
    </StructFormat>
    <StructFormat name='Trip' >
        <TagField type='String' value='Z1 '/>
        <FieldFormat name='TripNumber' length='6'/>
        <FieldFormat name='RegionNetz' length='2'/>
        <FieldFormat name='NationalProductionDate' length='10'/>
        <FieldFormat name='TrainTypeMainNumber' length='2'/>
        <FieldFormat name='TrainTypeSubNumber' length='1'/>
        <FieldFormat name='DepartureStationRL100' length='5'/>
        <FieldFormat name='DepartureStationUICRailAuthority' length='6'/>
        <FieldFormat name='DepartureStationNetworkLocation' length='6'/>
        <FieldFormat name='TargetTime' length='18'/>
        <FieldFormat name='RelativeTime' length='5' />
    </StructFormat>
    <StructFormat name='HandoverTakeover' >
        <TagField type='String' value='U1 '/>
        <FieldFormat name='HandoverTakeoverFlag' length='1'/>
        <FieldFormat name='ConsigningRU' length='4'/>
        <FieldFormat name='AcceptingRU' length='4'/>
        <FieldFormat name='UICBorderCode' length='3'/>
    </StructFormat>
</MessageFormat>

И в моем шаблоне xslt я хочу подсчитать (FieldFormat / @ length + string-length (TagField / @ value) каждого StructFormat непосредственно в MessageFormat:

<?xml version="1.0" encoding="UTF-8"?>
<?altova_samplexml format.xml?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:err="http://www.w3.org/2005/xqt-errors" xmlns:saxon="http://saxon.sf.net/" exclude-result-prefixes="array fn map math xhtml xs err" version="3.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:variable name="msg">H0 EVU_DBSRD PVG     W14 PVGERL  I                                        0142019-12-08-07.46.52.436704NNJNNJNM1           80270611 04401                        M2 08.12.201907:50:00Z1 BAU1    08.12.2019                    08.12.201907:50:00 0000R1 00131806940728280201912063946287201912061215058175346965                                   000NNJNNN                                  80270611 04401R1 00231806940476880201912063946287201912061215059494346965                                   000NNJNNN                                  80270611 04401R1 00331806948174180201912063946287201912061215050425346965                                   000NNJNNN                                  80270611 04401R1 00431806948098280201912063946287201912061215051864346965                                   000NNJNNN                                  80270611 04401</xsl:variable>
    <xsl:accumulator name="position-count" as="xs:double" initial-value="1" streamable="no">
        <xsl:accumulator-rule match="/MessageFormat/StructFormat" phase="end" select="$value +sum(.//FieldFormat/@length) + string-length(./TagField/@value)" />
    </xsl:accumulator>
    <xsl:template match="/">
        <output>
            <xsl:for-each select="/MessageFormat/StructFormat">
            <xsl:element name="{./@name}">
                <xsl:attribute name="start" select="fn:accumulator-before('position-count')"/>
                <xsl:attribute name="end" select="fn:accumulator-after('position-count')" />
                </xsl:element>
            </xsl:for-each>
        </output>
    </xsl:template>
</xsl:stylesheet>

Когда я запускаю его с XML Spy Professional 2020 SP1, я получаю вывод:

<?xml version="1.0" encoding="UTF-8"?>
<output xmlns:saxon="http://saxon.sf.net/">
    <TransportEventHeader start="1" end="111"/>
    <NotificationLocation start="111" end="162"/>
    <NotificationTime start="162" end="183"/>
    <Trip start="183" end="247"/>
    <HandoverTakeover start="247" end="262"/>
</output>

Но когда я запускаю его с Saxon 9-9-1-5 Java java -cp /d/SaxonPE9-9-1-5J/saxon9pe.jar net.sf.saxon.Transform -s:format.xml -xsl:accumulator.xslt -o:output.xml, я получаю ошибку:

Ошибка при оценке (fn: Accumulator-before (...)) в xsl: attribute / @ select в строке 13, столбце 83 файла аккумулятор. Xslt: XTDE3362: счетчик позиции аккумулятора не применим к текущему документу, вызванному неизвестным вызывающим (классом net.sf.saxon.expr.instruct.ForEach) в файле: / D: /xslt/accumulator.xslt#11 В шаблоне правило с match = "/" в строке 9 файла excumulator.xslt Счетчик позиций аккумулятора не применяется к текущий документ

Что я сделал с аккумулятором? Почему он работает с XML Spy, а не с Saxon 9.9?

На самом деле я хочу добавить условие в свой аккумулятор, чтобы проверить, возникает ли значение TagField/@value в переменной $msg в правильной позиции.

Например, для StructFormat[@name='TransportEventHeader'] первые 3 символа в $ msg - это «H0», поэтому он соответствует StructFormat[@name='TransportEventHeader']/TagField/@value, в этом случае длина должна быть добавлена ​​в мой аккумулятор, если нет, то ее не следует добавлять. Я не знаю, как это реализовать в аккумуляторе.


person dingjun    schedule 10.12.2019    source источник
comment
w3.org/TR/ 2014 / WD-xslt-30-20141002 / предполагает, что вы находитесь в потоковом режиме с Saxon, но не объявили, что аккумулятор является потоковым.   -  person Richard    schedule 10.12.2019
comment
Когда я установил streamable = yes, то помимо ошибки я получил еще и предупреждение: Предупреждение на xsl: Accumulator в строке 6, столбец 91 аккумулятора. Xslt: SXST0068: Запрос на потоковую передачу проигнорирован: эта конфигурация Saxon не поддерживает потоковую передачу. Нужно ли мне явно задавать конфигурацию Saxon для включения потоковой передачи?   -  person dingjun    schedule 10.12.2019
comment
Я проверил эту страницу, saxonica.com/html/documentation/sourcedocs / streaming /. В нем говорится, что для потоковой передачи требуется Saxon EE, поскольку я использую Saxon PE, поэтому потоковая передача не поддерживается?   -  person dingjun    schedule 10.12.2019
comment
@Richard, вы процитировали ранний рабочий проект спецификации XSLT 3.0, правила применения аккумуляторов были введены позже. См. w3.org/TR/xslt-30/#applicability-of. -аккумуляторы   -  person Michael Kay    schedule 10.12.2019


Ответы (2)


Правила здесь: https://www.w3.org/TR/xslt-30/#applicability-of-accumulators

Правило 5 гласит: Для документа, содержащего узлы, предоставленные при выборе начального соответствия, применимыми накопителями являются те, которые определены объявлением xsl: mode начального режима. Это означает, что в отсутствие объявления xsl: mode аккумуляторы не применимы.

Итак, вам нужно добавить

<xsl:mode use-accumulators="position-count"/>

Причина этих правил в спецификации заключается в том, что (а) при потоковой передаче дорого поддерживать аккумулятор для потокового документа, если он не будет использоваться в этом документе, и (б) хотя такие накладные расходы не существуют с документами без потоковой передачи, поскольку накопители могут оцениваться при первом использовании, считалось желательным иметь одно и то же правило, независимо от того, является ли документ потоковым или нет.

Altova не реализует потоковую передачу, поэтому они, вероятно, подумали (и с некоторым обоснованием, я бы согласился), что реализация правил - это большие усилия, которые не представляют большой ценности для пользователей.

person Michael Kay    schedule 10.12.2019
comment
Большое спасибо! Без вашего намека я не смог бы этого сделать самостоятельно. Мне интересно, кроме тех разработчиков движка xslt, сколько людей прочитают спецификацию w3 xslt. - person dingjun; 10.12.2019
comment
Люди изучают язык программирования по-разному: читая спецификацию, читая книги и учебные пособия, на учебных курсах, сидя рядом с Нелли, просматривая примеры и даже (судя по Stack Overflow) методом проб и ошибок. Избегание неожиданностей - один из критериев, который используют разработчики языков, но, в конце концов, нужно исходить из предположения, что люди, использующие языковую конструкцию, имеют доступ к информации о том, как она работает. - person Michael Kay; 10.12.2019

Майкл Кей ответил на мой вопрос. И вопрос изначально возник из-за применения гидроаккумулятора. Теперь у меня есть рабочий аккумулятор, как показано ниже, для расчета позиции группы:

        <xsl:accumulator-rule match="/MessageFormat/StructFormat" phase="end">
            <xsl:choose>
                <xsl:when test="substring($msg, $value, string-length(./TagField/@value)) = ./TagField/@value">
                    <xsl:value-of select="$value + xs:integer(sum(.//FieldFormat/@length)) + string-length(./TagField/@value)"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$value"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:accumulator-rule>
    </xsl:accumulator>
person dingjun    schedule 10.12.2019
comment
В качестве общего совета по использованию xsl:value-of по сравнению с xsl:sequence, я бы предложил использовать xsl:sequence во всех случаях, когда вы хотите, чтобы тело функции или правило аккумулятора возвращало значение определенного типа, например xs:integer, поскольку xsl:value-of всегда создает текстовый узел из выбранного select значение выражения, а xsl:sequence просто возвращает выбранное значение. - person Martin Honnen; 10.12.2019
comment
@MartinHonnen Спасибо за подсказку. Я думаю, что xsl:sequence представлен в XSLT 2.0., И я все еще не привык к нему, даже XSLT 3.0 присутствует. - person dingjun; 11.12.2019