2016-11-15 2 views
1

У меня есть XML-файл:Как улучшить XSLT-эффективность

Я думаю, вы могли бы понять мой XML как таблицу содержимого.
AElement @Name='1' является запись
Первый AElement @Name='2' будет запись 1.1
AElement @Name='3' ниже этого AElement @Name='2' бы непосредственно принадлежат ему делать им доступ 1.1.1, вход 1.1.2 и вступление 1.1 .3 и ввод 1.1.4
Второй AElement @Name='2' будет запись 1.2
и так далее ..

<ROOT> 
    <AElement Name="1"> 
     <AElement> 
      <Child1></Child1> 
      <Child2>0000</Child2> 
     </AElement> 
    </AElement> 
    <AElement Name="2"> 
     <AElement> 
      <Child1>E</Child1> 
      <Child2>1000</Child2> 
     </AElement> 
    </AElement> 
    <AElement Name="3"> 
     <AElement> 
      <Child1>E</Child1> 
      <Child2>0100</Child2> 
     </AElement> 
    </AElement> 
    <AElement Name="3"> 
     <AElement> 
      <Child1>U</Child1> 
      <Child2>0200</Child2> 
     </AElement> 
    </AElement> 
    <AElement Name="3"> 
     <AElement> 
      <Child1>E</Child1> 
      <Child2>0300</Child2> 
     </AElement> 
    </AElement> 
    <AElement Name="2"> 
     <AElement> 
      <Child1>E</Child1> 
      <Child2>2000</Child2> 
     </AElement> 
    </AElement> 
    <AElement Name="3"> 
     <AElement> 
      <Child1>N</Child1> 
      <Child2>0400</Child2> 
     </AElement> 
    </AElement> 
    <AElement Name="3"> 
     <AElement> 
      <Child1>E</Child1> 
      <Child2>0500</Child2> 
     </AElement> 
    </AElement> 
    <AElement Name="2"> 
     <AElement> 
      <Child1>E</Child1> 
      <Child2>3000</Child2> 
     </AElement> 
    </AElement> 
    <AElement Name="2"> 
     <AElement> 
      <Child1>U</Child1> 
      <Child2>4000</Child2> 
     </AElement> 
    </AElement> 
    <AElement Name="3"> 
     <AElement> 
      <Child1>E</Child1> 
      <Child2>0600</Child2> 
     </AElement> 
    </AElement> 
    <AElement Name="4"> 
     <AElement> 
      <Child1>E</Child1> 
      <Child2>0010</Child2> 
     </AElement> 
    </AElement> 
</ROOT> 

Wanted результат:

Для каждого AElement таблица должна быть создана
где для каждого AElement следующего шага
если AElement/Child1='E' этого AElement
необходимо создать таблицу-строку и таблицу-таблицу.
Эта таблица-ячейка должна быть заполнена значением AElement/Child2AElement.

Однако эта таблица должна быть создана только в том случае, если существует AElement следующего этапа с AElement/Child1='E'.

ПРИМЕР

Для каждого AElement @Name='2' таблица должна быть создана , где для каждого AElement @Name='3', который принадлежит AElement @Name='2'
, если AElement/Child1='E' из AElement @Name='3' таблица-строки и таблицы-ячейка должна быть создана этого таблицы- ячейка должна быть заполнена значением AElement/Child2 этого AElement @Name='3'.

Так что:

<AElement Name="2"> 
    <AElement> 
     <Child1>U</Child1> 
     <Child2>4000</Child2> 
    </AElement> 
</AElement> 
<AElement Name="3"> 
    <AElement> 
     <Child1>E</Child1> 
     <Child2>0600</Child2> 
    </AElement> 
</AElement> 
<AElement Name="4"> 
    <AElement> 
     <Child1>E</Child1> 
     <Child2>0010</Child2> 
    </AElement> 
</AElement> 

становится этим:

<fo:block>STEP 2 4000</fo:block> 

<fo:table> 
    <fo:table-row> 
     <fo:table-cell> 
      <fo:block> 
       0600 
      </fo:block> 
     </fo:table-cell> 
    </fo:table-row> 
</fo:table> 

НО это:

<AElement Name="2"> 
    <AElement> 
     <Child1>E</Child1> 
     <Child2>3000</Child2> 
    </AElement> 
</AElement> 
<AElement Name="2"> 
    <AElement> 
     <Child1>U</Child1> 
     <Child2>4000</Child2> 
    </AElement> 
</AElement> 

не будет создавать таблицу, поскольку STEP 3000 не имеет следующие AElements @Name='3'.


<fo:root> 

    <fo:block>STEP 1 0000</fo:block> 

    <fo:table> 
     <fo:table-row> 
      <fo:table-cell> 
       <fo:block> 
        1000 
       </fo:block> 
      </fo:table-cell> 
     </fo:table-row> 
     <fo:table-row> 
      <fo:table-cell> 
       <fo:block> 
        2000 
       </fo:block> 
      </fo:table-cell> 
     </fo:table-row> 
     <fo:table-row> 
      <fo:table-cell> 
       <fo:block> 
        3000 
       </fo:block> 
      </fo:table-cell> 
     </fo:table-row> 
    </fo:table> 



    <fo:block>STEP 2 1000</fo:block> 

    <fo:table> 
     <fo:table-row> 
      <fo:table-cell> 
       <fo:block> 
        0100 
       </fo:block> 
      </fo:table-cell> 
     </fo:table-row> 
     <fo:table-row> 
      <fo:table-cell> 
       <fo:block> 
        0300 
       </fo:block> 
      </fo:table-cell> 
     </fo:table-row> 
    </fo:table> 



    <fo:block>STEP 2 2000</fo:block> 

    <fo:table> 
     <fo:table-row> 
      <fo:table-cell> 
       <fo:block> 
        0500 
       </fo:block> 
      </fo:table-cell> 
     </fo:table-row> 
    </fo:table> 



    <fo:block>STEP 2 4000</fo:block> 

    <fo:table> 
     <fo:table-row> 
      <fo:table-cell> 
       <fo:block> 
        0600 
       </fo:block> 
      </fo:table-cell> 
     </fo:table-row> 
    </fo:table> 


    <fo:block>STEP 3 0600</fo:block> 

    <fo:table> 
     <fo:table-row> 
      <fo:table-cell> 
       <fo:block> 
        0010 
       </fo:block> 
      </fo:table-cell> 
     </fo:table-row> 
    </fo:table> 

</fo:root> 

<xsl:transform version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format" 
> 
    <xsl:output indent="yes" /> 



    <!-- all <AElement> we consider for output, indexed by their @Name and group ID --> 
    <xsl:key name="AElementGroup1" match="AElement[AElement/Child1 = 'E']" use=" 
     concat(@Name, '|', generate-id(preceding-sibling::AElement[@Name = '1'][1])) 
    " /> 
    <xsl:key name="AElementGroup2" match="AElement[AElement/Child1 = 'E']" use=" 
     concat(@Name, '|', generate-id(preceding-sibling::AElement[@Name = '2'][1])) 
    " /> 
    <xsl:key name="AElementGroup3" match="AElement[AElement/Child1 = 'E']" use=" 
     concat(@Name, '|', generate-id(preceding-sibling::AElement[@Name = '3'][1])) 
    " /> 
    <xsl:key name="AElementGroup4" match="AElement[AElement/Child1 = 'E']" use=" 
     concat(@Name, '|', generate-id(preceding-sibling::AElement[@Name = '4'][1])) 
    " /> 
    <xsl:key name="AElementGroup5" match="AElement[AElement/Child1 = 'E']" use=" 
     concat(@Name, '|', generate-id(preceding-sibling::AElement[@Name = '5'][1])) 
    " /> 
    <xsl:key name="AElementGroup6" match="AElement[AElement/Child1 = 'E']" use=" 
     concat(@Name, '|', generate-id(preceding-sibling::AElement[@Name = '6'][1])) 
    " /> 
    <xsl:key name="AElementGroup7" match="AElement[AElement/Child1 = 'E']" use=" 
     concat(@Name, '|', generate-id(preceding-sibling::AElement[@Name = '7'][1])) 
    " /> 

    <xsl:template match="/"> 
     <fo:root> 
     <fo:layout-master-set> 
     <fo:simple-page-master 
     master-name="DIN-A4-Landscape" 
     page-height="210mm" 
     page-width="297mm" 
     margin-left="1mm" 
     margin-right="1mm" 
     margin-top="1mm" 
     margin-bottom="1mm" 
      > 
      <fo:region-body margin="1mm"/> 
      <fo:region-before region-name="header" extent="5mm"/> 
      <fo:region-after region-name="footer" extent="15mm"/> 
      <fo:region-start region-name="left" extent="5mm"/> 
      <fo:region-end region-name="right" extent="5mm"/> 
     </fo:simple-page-master> 
     </fo:layout-master-set> 
     <fo:page-sequence master-reference="DIN-A4-Landscape"> 
     <fo:flow flow-name="xsl-region-body">      
      <xsl:call-template name="ink"> 
       <xsl:with-param name="Now" select="1"/> 
      </xsl:call-template> 
     </fo:flow> 
     </fo:page-sequence> 

     </fo:root> 
    </xsl:template> 

    <xsl:template name="ink"> 

    <xsl:param name="Now"/> 
    <xsl:param name="Next" select="$Now + 1"/> 
    <xsl:param name="Ende" select="3"/> 

    <xsl:apply-templates select="ROOT"> 
     <xsl:with-param name="nowStep" select="$Now"/> 
     <xsl:with-param name="nextStep" select="$Next"/> 
    </xsl:call-template> 

    <xsl:if test="$Ende > $Now"> 

     <xsl:call-template name="ink"> 
     <xsl:with-param name="Now" select="$Now + 1"/>  
    </xsl:call-template> 
    </xsl:if> 

    </xsl:template> 

    <xsl:template match="ROOT"> 
     <xsl:param name="nowStep"/> 
     <xsl:param name="nextStep"/> 

     <xsl:for-each select="AElement[@Name = $nowStep]"> 
      <xsl:variable name="groupId" select="generate-id()" />    
       <xsl:variable name="groupKey" select="concat($nextStep, '|', $groupId)" /> 
       <fo:block><xsl:value-of select="concat('STEP ' , $nowStep)" /></fo:block> 

<xsl:variable name="group"> 
    <xsl:value-of select="concat('InternalElementGroup',$nowStep)"/> 
</xsl:variable> 

<xsl:if test="count(key($group, $groupKey))>=1"> 

       <fo:table page-break-after="always"> 
        <fo:table-body> 
        <xsl:choose> 
        <xsl:when test="$nowStep = 1"> 
         <xsl:apply-templates select="key('AElementGroup1', $groupKey)/AElement" /> 
        </xsl:when> 
        <xsl:when test="$nowStep = 2"> 
         <xsl:apply-templates select="key('AElementGroup2', $groupKey)/AElement" /> 
        </xsl:when> 
        <xsl:when test="$nowStep = 3"> 
         <xsl:apply-templates select="key('AElementGroup3', $groupKey)/AElement" /> 
        </xsl:when> 
        </xsl:choose> 


        </fo:table-body> 
       </fo:table> 
</xsl:if>    
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template match="AElement/AElement"> 
     <fo:table-row> 
      <fo:table-cell> 
       <fo:block><xsl:value-of select="Child2"/></fo:block> 
      </fo:table-cell> 
     </fo:table-row> 
    </xsl:template> 

</xsl:transform> 

Этот код по @Tomalak возвращает желаемый результат.

+0

Да, 'count (previous-sibling' очень медленно. В C# я бы использовал Linq для Xml вместо XSLT. –

ответ

1

Это не на 100% ясно, что ваш намеченный выход с тех пор, как вы даете только один пример и никакого дальнейшего контекста.

Я делаю следующие предположения:

  1. Все элементы предварительно заказаны должным образом на входе.
  2. У вас есть несколько <AElement Name="1">, каждый из которых запускает новый «раздел».
  3. В каждом разделе вам нужно несколько <fo:block>STEP N</fo:block>, где N - имя @ каждого из <AElement>.
  4. Каждая из этих групп должна содержать элементы, которые относятся к порядковому положению следующего (то есть ШАГ 1 должен содержать элементы, которые имеют @Name = '2' и т. Д.). Это составляет в общей сложности 8 групп (N < = 8).
  5. В каждой из этих групп вы хотите: <fo:table> с M строками, где M - количество <AElement> элементов, которые имеют имя @Name и содержат <Child1>E</Child1>.
  6. Все вышеуказанные потребности, чтобы быть в XSLT 1,0

Таким образом, общий порядок обработки будет

  • для каждого AElement[@Name = '1']
    • для N = 1 .. 8
      • <fo:block>STEP N</fo:block>
      • выход <fo:table> with M rows for group (N+1) </fo:table>

Я не реалистичное 5000-элементный входной XML, чтобы проверить с, но вот как я бы решить эту проблему в XSLT 1.0.

<xsl:transform version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format" 
> 
    <xsl:output indent="yes" /> 

    <!-- all <AElement> we consider for output, indexed by their @Name and group ID --> 
    <xsl:key name="AElementGroup" match="AElement[AElement/Child1 = 'E']" use=" 
     concat(@Name, '|', generate-id(preceding-sibling::AElement[@Name = '1'][1])) 
    " /> 

    <!-- some random nodes, so we have something to count with --> 
    <xsl:variable name="counter" select="(//node())[position() &lt; 9]" /> 

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

    <xsl:template match="ROOT"> 
     <xsl:for-each select="AElement[@Name = '1']"> 
      <xsl:variable name="groupId" select="generate-id()" /> 
      <xsl:for-each select="$counter"> 
       <xsl:variable name="groupKey" select="concat(position() + 1, '|', $groupId)" /> 
       <fo:block><xsl:value-of select="concat('STEP ' , position())" /></fo:block> 
       <fo:table> 
        <fo:table-body> 
         <xsl:apply-templates select="key('AElementGroup', $groupKey)/AElement" /> 
        </fo:table-body> 
       </fo:table> 
      </xsl:for-each> 
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template match="AElement/AElement"> 
     <fo:table-row> 
      <fo:table-cell> 
       <fo:block><xsl:value-of select="Child2"/></fo:block> 
      </fo:table-cell> 
     </fo:table-row> 
    </xsl:template> 

</xsl:transform> 

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

+0

Ваши предположения были абсурдны правильно. Я просто обновил вопрос с помощью полного XML и xslt и pdf до ШАГ 3. Таким образом, общий порядок обработки будет: • для каждого AElement [@Name = '1'] (и он относится к текущему разделу «, как вы его называете) • для N = 1 .. 8 • выход STEP N • выход с рядами M для группы (N + 1)

+0

Хорошо, мой XSLT, кажется, чтобы сделать это. на моем компьютере она проходит через XML в чуть менее 10 секунд с помощью MSXML 4.0, как я использую [msxsl .exe] (https://www.microsoft.com/en-us/download/details.aspx?id=21714) для быстрого тестирования пробной версии. YMMV. Является ли результат * правильным * для вас, чтобы определить. – Tomalak

+0

Менее 10 секунд для STEP 1 или для всех STEP? –

Смежные вопросы