2017-03-27 9 views
1

영어로 내 문제를 설명하는 방법을 잘 모르겠습니다. 할려고합니다.XSL-T & XSL-FO : XML 데이터를 재구성하여 모든 페이지에 대해 페이지 시퀀스를 동적으로 생성합니다.

의 나는 다음과 같은 XML 데이터가 있다고 가정 해 봅시다 :

<ROOT> 
    <A> 
    <ID>A1</ID> 
    <DATA> 
     <ENTRY> 
     <ENTRYID>Entry1</ENTRYID> 
     <ITEM1>Item1</ITEM1> 
     <ITEM2>Item2</ITEM2> 
     <ITEM3>Item3</ITEM3> 
     </ENTRY> 
     <ENTRY> 
     <ENTRYID>Entry2</ENTRYID> 
     <ITEM1>Item2_1</ITEM1> 
     <ITEM2>Item2_1</ITEM2> 
     <ITEM3>Item2_3</ITEM3> 
     </ENTRY> 
     ... even more entries... 
    </DATA> 
    </A> 
    <A> 
    <ID>A2</ID> 
    <DATA> 
     <ENTRY> 
     <ENTRYID>Entry1</ENTRYID> 
     <ITEM1>foo</ITEM1> 
     <ITEM2>bar</ITEM2> 
     <ITEM3>andsoon</ITEM3> 
     </ENTRY> 
     <ENTRY> 
     <ENTRYID>Entry2</ENTRYID> 
     <ITEM1>even</ITEM1> 
     <ITEM2>more</ITEM2> 
     <ITEM3>items</ITEM3> 
     </ENTRY> 
     ... even more entries... 
    </DATA> 
    </A> 
    <A> 
    .. as many A-Elements as you can think of... 
    </A> 
</ROOT> 

로 A-요소 내 XML 데이터에있을 수 있습니다 또는 얼마나 많은 것은 ENTRY-요소는 A-요소 내부에 얼마나 많은에는 제한이 없습니다 .

그래서 모든 데이터를 하나의 큰 페이지 시퀀스 (XSL-FO) 안에 넣는 기존 XSL- 파일이 있습니다. XML과 XSL을 처리하기 위해 Apache FOP를 사용하고 있습니다. 출력 형식은 PDF입니다. XML 데이터가 매우 큰 경우 메모리 문제가 발생합니다. 큰 데이터를 처리 할 때 성능 및 메모리 소비를 조정하는 방법에 대해 많이 읽었으며 페이지 당 한 페이지 시퀀스로 데이터를 분할하려고합니다. 제가 직면 한 문제는 스타일 시트에서 데이터를 처리하기 전에 데이터를 분할하거나 재구성하는 방법을 모르겠다는 것입니다.

이제 내 스타일이 좀 깔끔하게 디자인 된 테이블에 데이터를 A와 항목에 대한 노드를 일치하고 포맷 :

<xsl:template match="A"> 
    ... print fancy title for table with A/ID ... 
    <fo:table> 
    <fo:table-header> 
     ... fancy table header here ... 
    </table-header> 
    <fo:table-body> 
     <xsl:apply-templates select="DATA/ENTRY"/> 
     <fo:table-row> 
     ... do some calculating for each A and create a sum table row ... 
     </fo:table-row> 
    </fo:table-body> 
    </fo:table> 
</xsl:template> 

<xsl:template match="ENTRY"> 
    <fo:table-row> 
    ... print Entry data in table cells ... 
    </fo:table-row> 
</xsl:template> 

a 요소는 페이지의 수백 (최악의 경우) 이상 늘릴 수있는 하나의 전체 테이블. 얼마나 많은 엔트리 요소가 한 페이지에 들어갈 수 있는지 알고 있습니다. 표 머리글과 합계 표 행으로 인해 하나의 A 요소의 첫 번째 페이지와 마지막 페이지는 그 사이에 페이지로 들어있는 항목의 수가 적습니다. 데이터를 적절한 청크로 분할해야합니다. XML 파일의 구조에 영향을 미치지 않으므로 스타일 시트에서 직접이 작업을 수행해야합니다.

데이터를 그룹화 할 때 제대로 작동하기 때문에 xsl : key를 사용하여 몇 가지 작업을 시도했지만 그룹화의 '특수'형식으로 작동하는지 여부는 확실하지 않습니다.

그래서 내 결과 XSL은 다음과 같아야합니다

<xsl:template match="/"> 
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> 
    <fo:layout-master-set>...</fo:layout-master-set> 

     <fo:page-sequence master-reference="{$master}"> 

     <fo:flow flow-name="xsl-region-body" font-size="10pt"> 

      <xsl:apply-templates select="A"/> 
      <xsl:apply-templates select="ENTRY elemnts for first page"/> 

     </fo:flow> 

     </fo:page-sequence> 

     <fo:page-sequence master-reference="{$master}"> 

     <fo:flow flow-name="xsl-region-body" font-size="10pt"> 

      <xsl:apply-templates select="ENTRY elemnts for pages in between"/> 

     </fo:flow> 

     </fo:page-sequence> 

     <fo:page-sequence master-reference="{$master}"> 

     <fo:flow flow-name="xsl-region-body" font-size="10pt"> 

      <xsl:apply-templates select="ENTRY elemnts for last page"/> 

     </fo:flow> 

     </fo:page-sequence> 

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

중간 페이지 순서가 하나 요소보다 더있을 수 있습니다 루프 물론이어야 있습니다. 모든 페이지 시퀀스의 모든 데이터를 적절하게 반복 처리하는 방법을 확신 할 수 없습니다.

답변

1
  1. 당신은 각 페이지의 순서가 '단지'전체 문서 수백 페이지의 배수에 수백 페이지까지 대신들 것이다 각 A에 대한 새로운 fo:page-sequence을 시작으로하여받을 수 있습니다.
  2. 재귀를 사용하여 다음 n ENTRY 요소를 선택하여 처리 할 수 ​​있습니다.
  3. XSLT 2.0을 사용하면 분명하고 명확한 코드가 생성되지만 xsl : key를 사용하여 그룹화 할 경우 XSLT 1.0을 사용하는 것처럼 보입니다.
  4. 생각하지 마세요. 루핑의 조건, 소스를 선택하고 처리한다는 측면에서 생각해보십시오. 결국 XSLT 1.0 또는 XSLT 2.0에서 업데이트 할 루핑 변수가 없습니다.마다의 하나 fo:page-sequence

는 A의 템플릿이된다 :

<xsl:template match="A"> 
    <fo:page-sequence master-reference="{$master}"> 
    <fo:flow flow-name="xsl-region-body" font-size="10pt"> 
     ... print fancy title for table with A/ID ... 
     <fo:table> 
     <fo:table-header> 
      ... fancy table header here ... 
     </table-header> 
     <fo:table-body> 
      <xsl:apply-templates select="DATA/ENTRY"/> 
      <fo:table-row> 
      ... do some calculating for each A and create a sum table row ... 
      </fo:table-row> 
     </fo:table-body> 
     </fo:table> 
    </fo:flow> 
    </fo:page-sequence> 
</xsl:template> 

재귀 솔루션은 아마도 여러 페이지의 경우뿐만 아니라 단일 페이지의 경우 처리가 필요 :

<xsl:param name="single-page-count" select="1" /> 
<xsl:param name="first-page-count" select="2" /> 
<xsl:param name="middle-page-count" select="3" /> 
<xsl:param name="last-page-count" select="2" /> 

<xsl:template match="ROOT"> 
    <fo:root> 
    <fo:layout-master-set> 
     <fo:simple-page-master master-name="a"> 
     <fo:region-body/> 
     </fo:simple-page-master> 
    </fo:layout-master-set> 
    <xsl:apply-templates select="A" /> 
    </fo:root> 
</xsl:template> 

<xsl:template match="A"> 
    <xsl:variable name="count" 
       select="count(DATA/ENTRY)" /> 

    <xsl:variable name="title"> 
    <xsl:call-template name="title" /> 
    </xsl:variable> 

    <xsl:variable name="sum-row"> 
    <xsl:call-template name="sum-row" /> 
    </xsl:variable> 

    <xsl:choose> 
    <xsl:when test="$count &lt;= $single-page-count"> 
     <xsl:call-template name="page"> 
     <xsl:with-param name="title" select="$title" /> 
     <xsl:with-param name="rows"> 
      <xsl:apply-templates select="DATA/ENTRY"/> 
     </xsl:with-param> 
     <xsl:with-param name="sum-row" select="$sum-row" /> 
     </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:call-template name="page"> 
     <xsl:with-param name="title" select="$title" /> 
     <xsl:with-param name="rows"> 
      <xsl:apply-templates 
       select="DATA/ENTRY[position() &lt;= $first-page-count]"/> 
     </xsl:with-param> 
     </xsl:call-template> 
     <xsl:call-template name="other-pages"> 
     <xsl:with-param name="entries" 
         select="DATA/ENTRY[position() > $first-page-count]" /> 
     <xsl:with-param name="sum-row" select="$sum-row" /> 
     </xsl:call-template> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template name="other-pages"> 
    <xsl:param name="entries" /> 
    <xsl:param name="sum-row" /> 
    <xsl:variable name="count" 
       select="count($entries)" /> 

    <xsl:choose> 
    <xsl:when test="$count &lt;= $last-page-count"> 
     <xsl:call-template name="page"> 
     <xsl:with-param name="rows"> 
      <xsl:apply-templates select="$entries"/> 
     </xsl:with-param> 
     <xsl:with-param name="sum-row" select="$sum-row" /> 
     </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:call-template name="page"> 
     <xsl:with-param name="rows"> 
      <xsl:apply-templates 
       select="$entries[position() &lt;= $middle-page-count]"/> 
     </xsl:with-param> 
     </xsl:call-template> 
     <xsl:call-template name="other-pages"> 
     <xsl:with-param name="entries" 
         select="$entries[position() > $middle-page-count]" /> 
     <xsl:with-param name="sum-row" select="$sum-row" /> 
     </xsl:call-template> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template name="page"> 
    <xsl:param name="title" /> 
    <xsl:param name="rows" /> 
    <xsl:param name="sum-row" /> 

    <fo:page-sequence master-reference="a"> 
    <fo:flow flow-name="xsl-region-body"> 
     <xsl:copy-of select="$title" /> 
     <fo:table> 
     <fo:table-header> 
      ... fancy table header here ... 
     </fo:table-header> 
     <fo:table-body> 
      <xsl:copy-of select="$rows" /> 
      <xsl:copy-of select="$sum-row" /> 
     </fo:table-body> 
     </fo:table> 
    </fo:flow> 
    </fo:page-sequence> 
</xsl:template> 

<xsl:template name="title"> 
    ... print fancy title for table <xsl:value-of select="ID"/> ... 
</xsl:template> 

<xsl:template name="sum-row"> 
    <fo:table-row> 
    ... do some calculating for each A and create a sum table row ... 
    </fo:table-row> 
</xsl:template> 
+0

재귀적인 접근 방식은 매력처럼 작동했습니다. 나는 단순히 데이터 주위를 반복해야한다고 생각하면서 오도 된 것이다. 고마워요! – Kaweoosh

+0

마지막 페이지가 중간 페이지보다 적은 행을 필요로한다고 생각하지 않았습니다. 난 멋진 제목, 페이지의 테이블에 대한 행 및 합계에 대한 세 개의 매개 변수를 취하는'fo : page-sequence'에 대한 명명 된 템플릿을 만들어 XSLT에서 리터럴 FO의 중복을 줄이는 코드도 업데이트했습니다. 열. 단일 페이지의 경우는 세 가지 매개 변수를 모두 제공합니다. 첫 번째 페이지의 경우, 제목과 행; 중간 페이지의 경우, 행만; 그리고 마지막 페이지의 경우, 행과 합계. –

+0

다시 한번 고마워요! – Kaweoosh