2015-06-11 1 views
0

В настоящее время я пытаюсь работать с группировкой в ​​XSLT 1.0. У меня есть XML, похожее на это:Суммирование на основе совпадающих значений XSLT-1.0

<table> 
    <row> 
     <PRODUCER type="VARCHAR" value="PRODUCER 1"/> 
     <PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION A"/> 
     <DOMESTIC type="DECIMAL" value="20"/> 
     <FOREIGN type="DECIMAL" value="4"/> 
    </row> 
    <row> 
     <PRODUCER type="VARCHAR" value="PRODUCER 1"/> 
     <PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION B"/> 
     <DOMESTIC type="DECIMAL" value="57"/> 
     <FOREIGN type="DECIMAL" value="10"/> 
    </row> 
    <row> 
     <PRODUCER type="VARCHAR" value="PRODUCER 2"/> 
     <PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION C"/> 
     <DOMESTIC type="DECIMAL" value="35"/> 
     <FOREIGN type="DECIMAL" value="20"/> 
    </row> 
    <row> 
     <PRODUCER type="VARCHAR" value="PRODUCER 2"/> 
     <PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION D"/> 
     <DOMESTIC type="DECIMAL" value="23"/> 
     <FOREIGN type="DECIMAL" value="18"/> 
    </row> 
</table> 

До сих пор я был в состоянии добиться всего, я надеялся получить за исключением суммы отечественных и зарубежных на основе ПРОИЗВОДИТЕЛЯ. Я прочитал в Muenchian grouping и подобных, но у меня возникли проблемы с его применением в моем XML. Я считаю, что мне нужно создать такой ключ, как следующий, основанный на ПРОИЗВОДИТЕЛЕ.

<xsl:key name="producerkey" match="/table/row/" use="PRODUCER/@value"/> 

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

До сих пор я мог сгенерировать PDF, подобный этому.

| PRODUCER || PUBLICATION ||DOMESTIC||FOREIGN| 
------------------------------------------ 
|PRODUCER 1||PUBLICATION A|| 20 || 4 | 
|   ||PUBLICATION B|| 57 || 10 | 
|   ||TOTALS  || DTOTAL || FTOTAL| 
|PRODUCER 2||PUBLICATION C|| 35 || 20 | 
|   ||PUBLICATION D|| 23 || 18 | 
|   ||TOTALS  || DTOTAL || FTOTAL| 

Я пытаюсь заменить «DTOTAL» и «Ftotal» суммы отечественных и зарубежных колонны с соответствующим ПРОИЗВОДИТЕЛЕМ группировкой.

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

<xsl:template match="row"> 
    <fo:table> 
     <fo:table-body font-size="10pt" 
         font-family="sans-serif" 
         line-height="10pt" 
         space-after.optimum="3pt"> 
      <xsl:for-each select="current()"> 
       <xsl:variable name="testnext" select="following-sibling::*[1]"/> 
       <xsl:choose> 
        <xsl:when test="$testnext"> 
         <xsl:choose> 
          <xsl:when test="$testnext/PRODUCER/@value = child::PRODUCER/@value"> 
           <fo:table-row> 
            <xsl:apply-templates select="PRODUCER"/> 
            <xsl:apply-templates select="PUBLICATION_CODE_-_NAME"/> 
            <xsl:apply-templates select="DOMESTIC"/> 
            <xsl:apply-templates select="FOREIGN"/> 
           </fo:table-row> 
          </xsl:when> 
          <xsl:otherwise> 
           <fo:table-row> 
          <xsl:apply-templates select="PRODUCER"/> 
          <xsl:apply-templates select="PUBLICATION_CODE_-_NAME"/> 
          <xsl:apply-templates select="DOMESTIC"/> 
          <xsl:apply-templates select="FOREIGN"/> 
         </fo:table-row> 
         <fo:table-row> 
          <fo:table-cell width="2.125in" 
              height="0.4in"> 
           <fo:block> 
            <fo:leader/> 
           </fo:block> 
          </fo:table-cell> 
          <fo:table-cell width="3.25in" 
              height="0.4in"> 
           <fo:block> 
            PRODUCER TOTAL 
           </fo:block> 
          </fo:table-cell> 
          <fo:table-cell width="0.95in" 
              height="0.4in"> 
           <fo:block> 
            DTOTAL 
           </fo:block> 
          </fo:table-cell> 
          <fo:table-cell width="0.95in" 
              height="0.4in"> 
           <fo:block> 
            FTOTAL 
           </fo:block> 
          </fo:table-cell> 
         </fo:table-row> 
          </xsl:otherwise> 
         </xsl:choose> 
        </xsl:when> 
        <xsl:otherwise> 
         <fo:table-row> 
          <xsl:apply-templates select="PRODUCER"/> 
          <xsl:apply-templates select="PUBLICATION_CODE_-_NAME"/> 
          <xsl:apply-templates select="DOMESTIC"/> 
          <xsl:apply-templates select="FOREIGN"/> 
         </fo:table-row> 
         <fo:table-row> 
          <fo:table-cell width="2.125in" 
              height="0.4in"> 
           <fo:block> 
            <fo:leader/> 
           </fo:block> 
          </fo:table-cell> 
          <fo:table-cell width="3.25in" 
              height="0.4in"> 
           <fo:block> 
            PRODUCER TOTAL 
           </fo:block> 
          </fo:table-cell> 
          <fo:table-cell width="0.95in" 
              height="0.4in"> 
           <fo:block> 
            DTOTAL 
           </fo:block> 
          </fo:table-cell> 
          <fo:table-cell width="0.95in" 
              height="0.4in"> 
           <fo:block> 
            FTOTAL 
           </fo:block> 
          </fo:table-cell> 
         </fo:table-row> 
        </xsl:otherwise> 
       </xsl:choose> 
      </xsl:for-each> 
     </fo:table-body> 
    </fo:table> 
</xsl:template> 

<xsl:template match="PRODUCER"> 
    <fo:table-cell width="2.125in" 
        height="0.2in"> 
     <fo:block> 
      <xsl:variable name="test" select="parent::row/preceding-sibling::row[1]"/> 
      <xsl:choose> 
       <xsl:when test="$test"> 
        <xsl:choose> 
         <xsl:when test="$test/PRODUCER/@value = @value"> 
          <fo:leader/> 
         </xsl:when> 
         <xsl:otherwise> 
          <xsl:value-of select="@value"/> 
         </xsl:otherwise> 
        </xsl:choose> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:value-of select="@value"/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </fo:block> 
    </fo:table-cell> 
</xsl:template> 

<xsl:template match="PUBLICATION_CODE_-_NAME"> 
    <fo:table-cell width="3.25in" 
        height="0.2in"> 
     <fo:block> 
      <xsl:value-of select="@value"/> 
     </fo:block> 
    </fo:table-cell> 
</xsl:template> 

<xsl:template match="DOMESTIC"> 
    <fo:table-cell width="0.95in" 
        height="0.2in"> 
     <fo:block> 
      <xsl:value-of select="@value"/> 
     </fo:block> 
    </fo:table-cell> 
</xsl:template> 

<xsl:template match="FOREIGN"> 
    <fo:table-cell width="0.95in" 
        height="0.2in"> 
     <fo:block> 
      <xsl:value-of select="@value"/> 
     </fo:block> 
    </fo:table-cell> 
</xsl:template> 

В основе того, что я делаю, чтобы проверить каждую строку для его ПРОИЗВОДИТЕЛЯ и использовать это сравнение, чтобы определить, когда включать стоимость производителя в первом столбце, и когда, чтобы создать строку, которая включает в себя сумму столбцы и дополнительное пространство. Я уверен, что мой код немного грязный, но я только начал работать с этой технологией и нашел, что кривая обучения немного крута для самостоятельного обучения. Кроме того, если это самая первая строка, то ПРОИЗВОДИТЕЛЬ включен, и если это последняя строка, то итоговая строка будет включена рядом с завершением отчета. Для того, что стоит, производители уже сгруппированы в соответствующем порядке.

Любая помощь и совет/критика будут очень оценены.

+0

'' ничего не делает , –

+0

Я вижу, что сейчас, спасибо за ответы. – speezy

ответ

1

Это намного проще в XSLT 2, но ради старой памяти:

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


<xsl:key name="producerkey" match="row" use="PRODUCER/@value"/> 

<xsl:template match="table"> 
    <table> 
    <thead> 
    <tr> 
    <th>Producer</th> 
    <th>Publication</th> 
    <th>Domestic</th> 
    <th>Foreigh</th> 
    </tr> 
    </thead> 
    <tbody> 
    <xsl:for-each select="row[ 
       generate-id(.) 
       = 
       generate-id(key('producerkey',PRODUCER/@value))[1] 
       ]"> 
    <xsl:for-each select="key('producerkey',PRODUCER/@value)"> 
     <tr> 
     <td>- 
     <xsl:if test="position()=1"> 
    <xsl:value-of select="PRODUCER/@value"/> 
     </xsl:if> 
     </td> 
     <td><xsl:value-of select="PUBLICATION_CODE_-_NAME/@value"/></td> 
     <td><xsl:value-of select="DOMESTIC/@value"/></td> 
     <td><xsl:value-of select="FOREIGN/@value"/></td> 
     </tr> 
    </xsl:for-each> 
    <tr> 
     <td>-</td> 
     <td>Totals</td> 
     <td><xsl:value-of select="sum(key('producerkey',PRODUCER/@value)/DOMESTIC/@value)"/></td> 
     <td><xsl:value-of select="sum(key('producerkey',PRODUCER/@value)/FOREIGN/@value)"/></td> 
    </tr> 
    </xsl:for-each> 
    </tbody> 
    </table> 
</xsl:template> 

</xsl:stylesheet> 

производит

<table><thead> 
    <tr><th>Producer</th><th>Publication</th><th>Domestic</th><th>Foreigh</th></tr></thead><tbody> 
    <tr> 
     <td>-PRODUCER 1</td><td>PUBLICATION A</td><td>20</td><td>4</td></tr> 
<tr><td>-</td><td>PUBLICATION B</td><td>57</td><td>10</td></tr> 
<tr><td>-</td><td>Totals</td><td>77</td><td>14</td></tr> 
<tr><td>- 
     PRODUCER 2</td><td>PUBLICATION C</td><td>35</td><td>20</td></tr> 
<tr><td>-</td><td>PUBLICATION D</td><td>23</td><td>18</td></tr> 
    <tr><td>-</td><td>Totals</td><td>58</td><td>38</td></tr> 
    </tbody> 
</table> 
+0

Спасибо за ваш ответ. Однако в вашем примере очень ясно, что я просто не могу применить эту технику к существующему коду. Если вы не возражаете, не могли бы вы уточнить, в какой момент кода, который я предоставил в своем вопросе, я бы создал идентификаторы? Или мне нужно переработать мой код, чтобы правильно группировать, а не использовать отношения родного брата? – speezy

+0

@speezy намного проще, если вы группируете, так как тогда у вас есть все узлы, которые нужно передать, и просто делайте 'sum()', если вы хотите использовать рекурсию sibling, вам нужно реструктурировать, чтобы не использовать шаблоны-приложения на дочерних узлах, но для просто применяйте шаблоны к следующему брату, передавая итоговые значения в качестве параметра. –

+0

Благодарим вас за все разъяснения. Я смог выполнить то, что мне нужно, основываясь на ваших ответах. Это очень ценится. – speezy