2013-10-12 21 views
2

У меня есть входной файл XML, который позволяет говорить shipnote.xml, который содержит список элементов. Частичные предметы имеют обычные атрибуты qty, partno и label. Каждому элементу присваивается номер packetno.xsl-fo, org.apache.fop.fo.ValidationException: «fo: table-body» отсутствует дочерние элементы

Я написал xsl-файл для создания pdf-shipnote из этих данных. Требование состоит в том, чтобы каждый packetno начинал с новой страницы в pdf-документе. На странице есть максимум 5 предметов.

Что я пытался сделать, сначала выберите различные PCKNO и перейди по этому разному packetno. Затем я вложил второй цикл внутри первого, чтобы получить статьи на PCKNO, чтобы напечатать их на судовом знаке.

После вы можете увидеть образец данных из ship.xml: требуется

root> 
items> 

item PCKNO="1" PCKCNT="2" > QTY>2/QTY> PARTNO>1518/PARTNO> LABEL>Part12/LABEL> /item> 
item PCKNO="1" PCKCNT="2" > QTY>1/QTY> PARTNO>1519/PARTNO> LABEL>Partxy/LABEL> /item> 
item PCKNO="2" PCKCNT="2" > QTY>3/QTY> PARTNO>1518/PARTNO> LABEL>Part12/LABEL> /item> 
item PCKNO="2" PCKCNT="2" > QTY>2/QTY> PARTNO>1519/PARTNO> LABEL>Partxy/LABEL> /item> 

/items> 

/root> 

Этот макет:

pdf-Page 1, <b>PCKNO:</b> 1 
qty | Partno | Label | 
----|--------|----------| 
2 | 1518 | Part123 | 
1 | 1519 | Partxyz | 

pdf-Page 2, <b>PCKNO:</b> 2 
qty | Partno | Label | 
----|--------|----------| 
3 | 1518 | Part123 | 
2 | 1520 | Partfour | 

Затем я применил XSL-таблицы стилей для удовлетворения требований.

Внешняя петля выполняется с:

fo:table table-layout='fixed' width="100%" > 
    !-- Columns of shipnote--> 
    fo:table-column /> 
    fo:table-column /> 
    fo:table-column /> 
    fo:table-header > 
     fo:table-row > 
      fo:table-cell><fo:block font-weight="bold">Qty /fo:block> /fo:table-cell> 
      fo:table-cell><fo:block font-weight="bold">Partno. /fo:block> /fo:table-cell> 
      fo:table-cell><fo:block font-weight="bold">Partname /fo:block> /fo:table-cell> 
     /fo:table-row > 
    /fo:table-header> 

    fo:table-body> 

!-- outer Loop get distinct pckno--> 
xsl:for-each select="items/item[not(@PCKNO=preceding-sibling::position/@PCKNO)]/@PCKNO" 
xsl:variable name="packno" select="."/>  
!-- inner loop get items per pckno--> 
xsl:for-each select="items/item[@PCKNO = $packno]" > 

    fo:table-row keep-together="always"> 
     !-- paximum of 5 parts per page--> 
     xsl:if test="position() mod 5 = 1"> 
      xsl:attribute name="break-before">page/xsl:attribute> 
     /xsl:if> 
     fo:table-cell>fo:block> xsl:value-of select="QTY"/> /fo:block> /fo:table-cell> 
     fo:table-cell>fo:block> xsl:value-of select="PARTNO"/> /fo:block> /fo:table-cell> 
     fo:table-cell>fo:block> xsl:value-of select="LABEL"/> /fo:block> /fo:table-cell> 
    /fo:table-row> 

/xsl:for-each> 

/xsl:for-each> 

Я использую эту команду ФОП: fop -xsl shiptest.xsl -xml shiptest.xml -pdf shiptest.pdf

Результат:

 Exception 

- org.apache.fop.apps.FOPException: <b>org.apache.fop.fo.ValidationException: "fo:table-body" is missing child elements. </b>Required content model: marker* (table-row+|table-cell+) (no contextinfo available) 

- javax.xml.transform.TransformerException: <b>org.apache.fop.fo.ValidationException: "fo:table-body" is missing child elements. </b>Required content model: marker* (table-row+|table-cell+) (no contextinfo available) 

Когда я раздеть внешний контур и использовать только внутренний контур с постоянным параметром 1, 2, он работает по желанию:

xsl:for-each select="items/item[@PCKNO = <b>1</b>]" /xsl:for-each 
    xsl:for-each select="items/item[@PCKNO = <b>2</b>]" /xsl:for-each 

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

ответ

3

Это XSL: для каждого- вы имеете проблемы с ....

<xsl:for-each select="items/item[not(@PCKNO=preceding-sibling::position/@PCKNO)]/@PCKNO"> 

Есть две проблемы с этим ...

  1. Вы делаете preceding-sibling::position , но нет имен элементов позиция в вашем XML.

  2. Вы выбираете атрибут @PCKNO в вашем XSL: для каждого- означает внутреннюю XSL: для каждого- будет относительно этого атрибута. Но ваш внутренний xsl: for-each выбирает пунктов/item, и поэтому он ничего не выберет.

Таким образом, «простой» исправить это изменить первый XSL: для-каждого к этому

<xsl:for-each select="items/item[not(@PCKNO=preceding-sibling::item/@PCKNO)]"> 

Таким образом, в этот момент вы позиционируются на пункт элемента. Поэтому вам необходимо изменить внутренний xsl: for-each, чтобы он возвращался к родительскому элементу, и затем может выбрать все элементы 4 с таким же атрибутом @PCKNO.

<xsl:for-each select="../item[@PCKNO = $packno]"> 

Стоит отметить, что использование предшествующее-родственный IsNot особый эффективный способ для поиска различных элементов. В XLST 1.0 наиболее эффективным способом группировки является использование метода Muenchian Grouping. Кроме того, если вы можете использовать XSLT 2.0, вы можете использовать xsl: для каждой группы.

+0

И вы должны добавить тест в будущем, окружающий всю таблицу, если ничто не соответствует вашим строкам цикла. Это позволит избежать возможных ошибок в будущем для пустых тел таблицы. –

+0

Это должен быть принятый ответ. – mcfea

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