XSLT для каждого, пытаясь создать структуру строки заголовка - PullRequest
1 голос
/ 14 июля 2020

Это не XSLT типа браузера, он предназначен для обработки данных (SAP B1 Integration Framework). Предположим, у нас есть две SQL таблицы, HEADER и LINE, и мы хотим избежать такой работы, когда мы сначала выбираем из заголовка, а затем запускаем отдельный выбор для строк для каждой, потому что это требует "визуального программирования", и мы нравится писать код больше, чем соединять стрелки. Итак, мы отправляем серверу запрос типа SELECT * FROM HEADER, SELECT * FROM LINES и получаем XML примерно так:

<ResultSets>
<ResultSet>
    <Row><MHeaderNum>1</MHeaderNum></Row>
    <Row><MHeaderNum>2</MHeaderNum></Row>
    <Row><MHeaderNum>3</MHeaderNum></Row>
</ResultSet>

<ResultSet>
    <Row><LineNum>1</LineNum> <HeaderNum>1</HeaderNum></Row>
    <Row><LineNum>2</LineNum> <HeaderNum>2</HeaderNum></Row>
    <Row><LineNum>1</LineNum> <HeaderNum>3</HeaderNum></Row>
    <Row><LineNum>2</LineNum> <HeaderNum>1</HeaderNum></Row>
    <Row><LineNum>1</LineNum> <HeaderNum>2</HeaderNum></Row>
    <Row><LineNum>2</LineNum> <HeaderNum>3</HeaderNum></Row>
</ResultSet>

, поэтому мы считаем себя обязательными процедурными программистами и получаем

<xsl:for-each select="//ResultSets/Resultset[1]/Row">
   do stuff with header data
   <xsl:for-each select="//ResultSets/Resultset[2]/Row[HeaderNum=MHeaderNum]">
      do stiff with the line data beloning to this particular header
   </xsl:for-each>  
</xsl:for-each>

И, конечно, это не работает, потому что MHeaderNum вышел из контекста, как гранж вышел из моды, и мы не можем сохранить его в переменной, потому что мы не будем обновлять эту переменную, поскольку XSLT - это своего рода неизменный функциональный язык программирования.

Но не бойтесь, говорит внутренний голос, потому что гуру XSLT могут решать подобные вещи с помощью шаблонов. Шаблоны, насколько я понимаю, являются своего рода XSLT-функциями. Они могут быть рекурсивными и тому подобное. Так можно ли их использовать для решения подобных проблем?

И, конечно же, мы говорим о XSLT 1.0, потому что я не знаю, беспокоился ли Java когда-либо о внедрении более поздних версий, но SAP определенно не беспокоился для использованной гипотетической реализации.

Или мне действительно стоит забыть об этом и просто соединить визуальные стрелки? Дело в том, что SQL не предполагается использовать в такой итерации по заголовкам, а затем по строкам. Что я пытаюсь сделать, так это то, что делает базу данных SQL счастливой, извлекаю из нее большой кусок данных и затем обрабатываю его где-нибудь в другом месте, не утруждая его семидесяти миллиардами крошечных запросов. И в нашем случае где-то еще, к сожалению, XSLT, хотя технически я мог бы попробовать JavaScript, а также SAP добавил Nashorn в эту кучу беспорядка, но, может быть, это разрешимо в «чистом» XSL?

Ответы [ 3 ]

1 голос
/ 14 июля 2020

Независимо от того, XSLT 1 или новее, с шаблонами и для каждого, существует функция current(): //ResultSets/Resultset[2]/Row[HeaderNum=current()/MHeaderNum].

1 голос
/ 14 июля 2020

Лучший способ разрешить перекрестные ссылки - использовать ключ . Например, следующая таблица стилей:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="line-by-header" match="ResultSet[2]/Row" use="HeaderNum" />

<xsl:template match="/ResultSets">
    <output>    
        <xsl:for-each select="ResultSet[1]/Row">
            <header num="{MHeaderNum}"> 
                <xsl:for-each select="key('line-by-header', MHeaderNum)">
                    <line>
                        <xsl:value-of select="LineNum"/>
                    </line>
                </xsl:for-each>
            </header>
        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>

при применении к следующему входу:

XML

<ResultSets>
    <ResultSet>
        <Row><MHeaderNum>1</MHeaderNum></Row>
        <Row><MHeaderNum>2</MHeaderNum></Row>
        <Row><MHeaderNum>3</MHeaderNum></Row>
    </ResultSet>
    <ResultSet>
        <Row><LineNum>1</LineNum> <HeaderNum>1</HeaderNum></Row>
        <Row><LineNum>2</LineNum> <HeaderNum>2</HeaderNum></Row>
        <Row><LineNum>3</LineNum> <HeaderNum>3</HeaderNum></Row>
        <Row><LineNum>4</LineNum> <HeaderNum>1</HeaderNum></Row>
        <Row><LineNum>5</LineNum> <HeaderNum>2</HeaderNum></Row>
        <Row><LineNum>6</LineNum> <HeaderNum>3</HeaderNum></Row>
    </ResultSet>
</ResultSets>

вернет:

Результат

<?xml version="1.0" encoding="UTF-8"?>
<output>
  <header num="1">
    <line>1</line>
    <line>4</line>
  </header>
  <header num="2">
    <line>2</line>
    <line>5</line>
  </header>
  <header num="3">
    <line>3</line>
    <line>6</line>
  </header>
</output>
0 голосов
/ 14 июля 2020

Вы можете попробовать следующий XSLT. Он использует три шаблона XSLT.

Поскольку желаемый результат неизвестен, я произвел произвольную обработку для каждого из шаблонов заголовков и позиций.

XSLT

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

    <xsl:template match="/">
        <root>
            <xsl:apply-templates/>
        </root>
    </xsl:template>

    <xsl:template match="/ResultSets/ResultSet[1]">
        <ResultSet1>
            <xsl:for-each select="Row">
                <r>
                    <xsl:value-of select="MHeaderNum"/>
                </r>
            </xsl:for-each>
        </ResultSet1>
    </xsl:template>

    <xsl:template match="/ResultSets/ResultSet[2]">
        <ResultSet2>
            <xsl:for-each select="Row">
                    <xsl:copy-of select="."/>
            </xsl:for-each>
        </ResultSet2>
    </xsl:template>
</xsl:stylesheet>
...