Группировка в XSLT3 с потоковой передачей xsl, но с ошибкой «Правило шаблона не является потоком» - PullRequest
0 голосов
/ 11 января 2019

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

Входной XML:

<AreaRoot>
<TableAndCaptionArea generated-by="table" id="t0005-tSC"  height="90.488pt" display-role="block">
<a>One</a>
</TableAndCaptionArea>
<TableAndCaptionArea generated-by="table" id="t0005-tSC" height="33.3pt" display-role="block">
<a>Two</a>
</TableAndCaptionArea>
<TableAndCaptionArea generated-by="table" id="t0005-tDC" height="91.594pt" display-role="block">
<a>Three</a>
</TableAndCaptionArea>
<TableAndCaptionArea generated-by="table" id="t0005-tLS" height="91.594pt" display-role="block">
<a>Four</a>
</TableAndCaptionArea>
</AreaRoot>

XSLT 3.0:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">

<!--xsl:mode streamable="yes"/-->
<xsl:mode streamable="yes" on-no-match="shallow-copy"/>

<xsl:output method="text"/>

<xsl:template match="/">
    <xsl:fork>
        <xsl:for-each-group select="descendant::*:TableAndCaptionArea[@id]" composite="yes" group-by="@id">
            <table>
                <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                <!--Height of a table -->
                <xsl:attribute name="height">
                    <xsl:variable name="var1">
                        <a>
                            <xsl:for-each select="current-group()/@height">
                                <b><xsl:value-of select="replace(., 'pt', '')"/></b>
                            </xsl:for-each>
                        </a>
                    </xsl:variable>
                    <xsl:value-of select="sum($var1/*:a/*:b)"/>
                </xsl:attribute>
            </table>
        </xsl:for-each-group>
    </xsl:fork>
</xsl:template>

</xsl:stylesheet>

Ошибка при запуске:

    Error on line 8 of Stream2.xsl:
XTSE3430: Template rule is not streamable
* The xsl:for-each-group/@select expression has crawling posture (that is, itcan select   overlapping nodes)

Требуемый результат:

<ATRinfo>
    <height>
    <table id="t0005-tSC" height="123.788"/>
    <table id="t0005-tDC" height="91.594" />
    <table id="t0005-tLS" height="91.594"/>
    </height>
</ATRinfo>

Использование версии SaxonEE9-9-0-2J. Подскажите пожалуйста, как устранить ошибку.

Ответы [ 2 ]

0 голосов
/ 16 января 2019

С помощью https://stackoverflow.com/a/44291127/3049413 (предложение Мартина Хоннена, сэр) моя программа немного изменилась, как показано ниже

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
<xsl:mode streamable="yes" on-no-match="shallow-copy"/>

<xsl:template match="/">
    <xsl:element name="ATRinfo">
    <xsl:fork>
        <xsl:for-each-group select="copy-of(descendant::*:TableAndCaptionArea[@id])" 
                        group-by="@id">
            <table>
                <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                <!--Height of a table -->
                <xsl:attribute name="height">
                    <xsl:variable name="var1">
                        <a>
                            <xsl:for-each select="current-group()/@height">
                                <b><xsl:value-of select="replace(., 'pt', '')"/></b>
                            </xsl:for-each>
                        </a>
                    </xsl:variable>
                    <xsl:value-of select="sum($var1/*:a/*:b)"/>
                </xsl:attribute>
            </table>
        </xsl:for-each-group>
    </xsl:fork>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>
0 голосов
/ 11 января 2019

Поскольку элементы, которые нужно сгруппировать, выглядят как братья и сестры, вам не нужна ось-потомок, чтобы найти их, вы можете использовать

<xsl:for-each-group select="/*/TableAndCaptionArea" 

Если в ваших фактических данных элементы не являются братьями и сестрами и встречаются на разных уровнях, но не являются рекурсивными, то вы также можете использовать innermost(//TableAndCaptionArea)

Также: вам не нужен составной = "да", потому что @id выбирает одно значение

и: вычисление высоты может быть упрощено до:

<xsl:attribute name="height" 
    select="sum(current-group() ! number(replace(@height, 'pt', ''))">
...