XSLT Группировка токенизированных значений по условию - PullRequest
0 голосов
/ 10 июля 2019

Мне трудно сгруппировать повторяющиеся элементы в новый XML.

Мой входной файл

<Load>
    <DataArea>
        <tag>
            <row>A,Header</row>
        </tag>

        <tag>
            <row>B,20190701</row>
        </tag>
        <tag>
            <row>C,12345, 100.00, 200.00</row>
        </tag>
        <tag>
            <row>D,001, 25.00</row>
        </tag>
        <tag>
            <row>D,002, 35.00</row>
        </tag>
        <tag>
            <row>D,003, 45.00</row>
        </tag>

        <tag>
            <row>B,20190702</row>
        </tag>
        <tag>
            <row>C,12345, 300.00, 400.00</row>
        </tag>
        <tag>
            <row>D,004, 55.00</row>
        </tag>
        <tag>
            <row>D,005, 65.00</row>
        </tag>
        <tag>
            <row>D,006, 75.00</row>
        </tag>

    </DataArea>
</Load>

Мне нужно разбить значения элементов через запятую и преобразовать их в структуру xml ниже.

<Load>
    <DataArea>
        <Header>
            <A>Header</A>
        </Header>

        <Line>
            <!-- July 1 Record -->
            <B>20190701</B>
            <C>12345</C>
            <D>
                <code>001</code>
                <amount>25.00</amount>
            </D>
            <D>
                <code>002</code>
                <amount>35.00</amount>
            </D>
            <D>
                <code>003</code>
                <amount>45.00</amount>
            </D>
        </Line>

        <Line>
            <!-- July 2 Record -->
            <B>20190702</B>
            <C>12345</C>
            <D>
                <code>004</code>
                <amount>55.00</amount>
            </D>
            <D>
                <code>005</code>
                <amount>65.00</amount>
            </D>
            <D>
                <code>006</code>
                <amount>75.00</amount>
            </D>
        </Line>
    </DataArea>
</Load>

Есть 2 <Lines></Lines>, потому что есть только две даты 1 июля и июля 2 . Даты представлены как значения для элемента <B>

Существует несколько <D> для каждого <Line>

Моя проблема в том, что я не могу сгруппировать <B><C> и <D> вместе, заключенные в <Line>. <D> должны принадлежать <B> или дате.

Ниже мой xslt-код.

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*" />
    <xsl:template match="/">
        <Load>
            <DataArea>
                <Header>
                    <A>
                        <xsl:for-each select="Load/DataArea/tag">
                            <xsl:variable name="col"
                                select="tokenize(current(),',')" />
                            <xsl:if test="$col[1] = 'A' ">
                                <xsl:value-of select="$col[2]" />
                            </xsl:if>
                        </xsl:for-each>

                    </A>
                </Header>

                <xsl:for-each select="Load/DataArea/tag">
                    <xsl:variable name="column"
                        select="tokenize(current(),',')" />
                    <Line>
                        <xsl:if test="$column[1] = 'B' ">
                            <B>
                                <xsl:value-of select="$column[2]" />
                            </B>
                        </xsl:if>
                        <xsl:if test="$column[1] = 'C' ">
                            <C>
                                <xsl:value-of select="$column[2]" />
                            </C>
                        </xsl:if>
                        <xsl:for-each select="../tag">
                            <xsl:variable name="column"
                                select="tokenize(current(),',')" />
                            <xsl:if test="$column[1] = 'D' ">
                                <D>
                                    <code>
                                        <xsl:value-of select="$column[2]" />
                                    </code>
                                    <amount>
                                        <xsl:value-of select="$column[3]" />
                                    </amount>
                                </D>
                            </xsl:if>
                        </xsl:for-each>
                    </Line>
                </xsl:for-each>
            </DataArea>
        </Load>
    </xsl:template>
</xsl:stylesheet>

Я получаю все <D> за цикл вместо только тех, которые принадлежат дате / <B> Повторяет все <D> и <Line>

Я не уверен, как решить эту проблему, особенно в том, что мне нужно их маркировать.

Буду признателен за любую помощь.

Спасибо.

1 Ответ

0 голосов
/ 10 июля 2019

Я думаю, что это может быть работа для xsl:for-each-group с атрибутом group-starting-with.

Попробуйте этот XSLT, который я также упростил, получив заголовок A с использованием базовой starts-with функциональности

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:template match="/">
    <Load>
      <DataArea>
        <Header>
          <A>
            <xsl:value-of select="substring-after(Load/DataArea/tag[starts-with(row, 'A,')], ',') " />
          </A>
        </Header>          
        <xsl:for-each-group select="Load/DataArea/tag[not(starts-with(row, 'A,'))]" group-starting-with="tag[starts-with(row, 'B,')]">
          <Line>
            <xsl:for-each select="current-group()">
              <xsl:variable name="column" select="tokenize(row,',')" />
              <xsl:element name="{$column[1]}">
              <xsl:choose>
                <xsl:when test="$column[1] = 'B' or $column[1] = 'C'">
                  <xsl:value-of select="$column[2]" />
                </xsl:when>
                <xsl:otherwise>
                  <code>
                    <xsl:value-of select="$column[2]" />
                  </code>
                  <amount>
                    <xsl:value-of select="$column[3]" />
                  </amount>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:element>
            </xsl:for-each>
          </Line>
        </xsl:for-each-group>
      </DataArea>
    </Load>
  </xsl:template>
</xsl:stylesheet>
...