Необходимо динамически изменять мастер-имя мастера простой страницы.

У меня есть XML-документ, как показано ниже. Каждый повторяющийся документ представляет собой страницу в файле PDF.

<AFPXMLFile>
    <docs>
      <regList>
           <region>1</region>
           <secList>
               <col>1</col>
               <lines></lines>
          </secList>
     </regList>
     <regList>
         <region>2</region>
         <secList>
               <col>2</col>
               <lines>
                  <line>IBM BELGIUM xxx</line>
                  <line>xxxxxx</line>
                  <line>xxxx</line>
              </lines>
         </secList>
     </regList>
     <regList></regList>
     <regList></regList>
  </docs>
  <docs></docs>
 </AFPXMLFile>

Мой XSL выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="fo">

<xsl:template match="AFPXMLFile">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master page-width="21cm" page-height="29.7cm"  margin-top="1.27cm" margin-bottom="1.27cm" margin-left="1.75cm" master-name="A4">
  <fo:region-body   margin-top="1mm" margin-bottom="1mm"/>
  <fo:region-before extent="0mm"/>
  <fo:region-after  extent="0mm"/>
  <fo:region-start  writing-mode="tb-rl" precedence="true" extent="10mm" />  
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4" font-family="sans-serif">
<xsl:for-each select="docs">
    <xsl:for-each select="./regList">
        <xsl:choose>
            <xsl:when test="region = 1">
               <fo:static-content flow-name="xsl-region-before">
                    <xsl:for-each select="./secList/lines">
                        <xsl:for-each select="node()">
                            <fo:block font-size="8pt" color="purple">
                                <xsl:value-of select="."/>
                           </fo:block>                                 
                        </xsl:for-each>
                     </xsl:for-each>
                </fo:static-content>
            </xsl:when>
            <xsl:when test="region = 2">
               <fo:static-content flow-name="xsl-region-start">
                    <xsl:for-each select="./secList/lines">
                        <xsl:for-each select="node()">
                                <fo:block font-size="4pt" padding-before="4pt" text-align="left" color="green">
                                    <xsl:value-of select="."/>
                                </fo:block> 
                        </xsl:for-each>
                     </xsl:for-each>
                 </fo:static-content>    
            </xsl:when>
            <xsl:when test="region = 3">
                <fo:static-content flow-name="xsl-region-body">
                    <xsl:for-each select="./secList/lines">
                        <xsl:for-each select="node()">
                            <fo:block font-size="8pt" color="blue">
                                <xsl:value-of select="."/>
                            </fo:block>
                         </xsl:for-each>
                    </xsl:for-each>
                </fo:static-content>
            </xsl:when>
            <xsl:when test="region = 4">
               <fo:flow flow-name="xsl-region-after">
                    <xsl:for-each select="./secList">
                        <xsl:for-each select="./lines">
                            <xsl:for-each select="node()">
                                <fo:block font-size="8pt" color="orange">
                                    <xsl:value-of select="."/>
                               </fo:block>
                            </xsl:for-each>
                        </xsl:for-each>
                     </xsl:for-each>
               </fo:flow>      
            </xsl:when>  
        </xsl:choose>                        
    </xsl:for-each>
</xsl:for-each>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>

Когда я запускаю преобразование, я получаю следующую ошибку:

org.apache.fop.fo.ValidationException: для «fo:page-sequence» «fo:static-content» должен быть объявлен перед «fo:flow»! (Контекстная информация недоступна)

Это я подозреваю, потому что он повторяет область статического содержимого для каждой страницы. Поэтому я считаю, что мне нужно изменить simple-page-master:master-name для каждой страницы, с которой мне нужна помощь.


person Madhu    schedule 11.08.2017    source источник


Ответы (1)


Согласно рекомендации XSL-FO, содержимое 'fo:page -последовательность' это:

(название?,префикс-фолио?,суффикс-фолио?,статическое-содержимое*,поток+)

это означает, что все элементы fo:static-content должны быть перед элементами fo:flow.

Ваша таблица стилей динамически создает либо fo:static-content (если region равно 1, 2 или 3), либо fo:flow (если region равно 4). Из сокращенного входного файла в вашем вопросе невозможно увидеть, всегда ли правильно сортируются элементы regList, чтобы они давали правильный результат при последовательной обработке.

Более того, поскольку каждый элемент docs представляет отдельный документ с разными верхними и нижними колонтитулами, вам необходимо создать отдельные fo:page-sequence вместо одного (иначе вы получите слишком много статического содержимого и потоков для одной последовательности страниц):

<xsl:for-each select="docs">
    <fo:page-sequence master-reference="A4" font-family="sans-serif">
        <xsl:for-each select="./regList">
            ....
        </xsl:for-each>
    </fo:page-sequence>
</xsl:for-each>

Кроме того, в таблице стилей есть странная вещь: вы сопоставляете fo:static-content с регионом xsl-region-body, а fo:flow с регионом xsl-region-after, что довольно необычно. Если «настоящим» содержимым для основной области является область с region = 3, вы должны обработать region 1, 2 и 4 сначала, а затем область 3:

<xsl:for-each select="docs">
    <fo:page-sequence master-reference="A4" font-family="sans-serif">
        <!-- create static contents -->
        <xsl:apply-templates select="./regList[region != '3']"/>
        <!-- create flow -->
        <xsl:apply-templates select="./regList[region = '3']"/>
    </fo:page-sequence>
</xsl:for-each>

с дополнительным шаблоном для соответствия reglist:

<xsl:template match="regList">
    <xsl:choose>
        <xsl:when test="region = '1'">
           <fo:static-content flow-name="xsl-region-before">
                <xsl:for-each select="./secList/lines">
                    <xsl:for-each select="node()">
                        <fo:block font-size="8pt" color="purple">
                            <xsl:value-of select="."/>
                       </fo:block>                                 
                    </xsl:for-each>
                 </xsl:for-each>
            </fo:static-content>
        </xsl:when>
        <xsl:when test="region = '2'">
           <fo:static-content flow-name="xsl-region-start">
                <xsl:for-each select="./secList/lines">
                    <xsl:for-each select="node()">
                            <fo:block font-size="4pt" padding-before="4pt" text-align="left" color="green">
                                <xsl:value-of select="."/>
                            </fo:block> 
                    </xsl:for-each>
                 </xsl:for-each>
             </fo:static-content>    
        </xsl:when>
        <xsl:when test="region = '3'">
            <fo:flow flow-name="xsl-region-body">
                <xsl:for-each select="./secList/lines">
                    <xsl:for-each select="node()">
                        <fo:block font-size="8pt" color="blue">
                            <xsl:value-of select="."/>
                        </fo:block>
                     </xsl:for-each>
                </xsl:for-each>
            </fo:flow>
        </xsl:when>
        <xsl:when test="region = '4'">
           <fo:static-content flow-name="xsl-region-after">
                <xsl:for-each select="./secList">
                    <xsl:for-each select="./lines">
                        <xsl:for-each select="node()">
                            <fo:block font-size="8pt" color="orange">
                                <xsl:value-of select="."/>
                           </fo:block>
                        </xsl:for-each>
                    </xsl:for-each>
                 </xsl:for-each>
           </fo:static-content>      
        </xsl:when>
    </xsl:choose>
</xsl:template>

или несколько небольших шаблонов:

<xsl:template match="reglist[region = '1']">
   <fo:static-content flow-name="xsl-region-before">
        <xsl:for-each select="./secList/lines">
            <xsl:for-each select="node()">
                <fo:block font-size="8pt" color="purple">
                    <xsl:value-of select="."/>
                </fo:block>                                 
            </xsl:for-each>
        </xsl:for-each>
    </fo:static-content>
</xsl:template>

<xsl:template match="reglist[region = '2']">
    ...
</xsl:template>

...
person lfurini    schedule 12.08.2017
comment
Спасибо за ответ на мой вопрос. Я новичок в ФОП. Да, regList всегда сортируется как 1,2,3 и 4 в элементе docs. XSL работает для первой страницы PDF и дает сбой, когда снова встречается с областью 1 для следующей страницы. Причина, по которой у меня есть fo:flow для региона-после, заключается в том, что когда я добавлял его перед любым другим регионом, он выдавал мне ошибку, говорящую, что весь статический контент должен располагаться перед потоком. Я понятия не имею, как я могу изменить цикл, чтобы они не повторялись. Не могли бы вы дать мне указатели. - person Madhu; 12.08.2017
comment
Спасибо за обновления. Я использовал ваше первое решение, и оно работает. - person Madhu; 12.08.2017