I am developing a pdf print publication with xsl-fo (Saxon XSL 2.0, AHF V6.2).
My goal is to have auto-numbered footnotes (excluding duplicates on a single page) with inserted text from referenced static text elements.
So basically inline footnotes (fn) do reference a static footnote text element, create an inline number and print the according footnote text at the bottom of the page.
<?xml version="1.0" encoding="UTF-8"?>
<document>
<chapter>
<paragraph>some description...</paragraph>
<paragraph>some description with a footnote <fn id="fn2"/></paragraph>
<paragraph>some description with a footnote <fn id="fn2"/></paragraph>
<paragraph>some description...</paragraph>
<paragraph>some description with a footnote <fn id="fn1"/></paragraph>
</chapter>
<!-- this is a wrapper element that will not be displayed in the rendered pdf but only contains the needed information for different footnote texts -->
<chapter class="footnoteWrapper">
<footnote id="fn1">
This is the text body of footnote #1.
</footnote>
<footnote id="fn2">
This is the text body of footnote #2.
</footnote>
<footnote id="fn3">
This is the text body of footnote #3.
</footnote>
</chapter>
</document>
Duplicate inline footnotes in a chapter have to show the same number according to the footnote they are pointing to.
This is what the result should look like...
Is it possible to achieve these goals with the AHF footnote extensions and the fo:footnote elements?
The AntennaHouse Formatter extentions do deliver strange behaviour if I´m using them for fn counting. They do continue counting (1, 2, 3) instead of refereing to the correct and current number of the referenced footnote.
This is the XSL so far (just the relevant snippet):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="fn[#id = //footnote/#nodeid]"
mode="content"
priority="7">
<!--+ fn link
|
| basic fn (inline) link template.
|
+-->
<xsl:apply-templates select="//footnote[#id = current()/#id]"
mode="content"/>
</xsl:template>
<xsl:template match="footnote"
mode="content"
priority="5">
<!--+ footnote
|
| basic footnote template.
|
+-->
<fo:footnote xsl:use-attribute-sets="fnt.footnote">
<fo:inline baseline-shift="super">
<axf:footnote-number id="fn_{#id}"/>
</fo:inline>
<fo:footnote-body space-after="1mm">
<fo:list-block provisional-distance-between-starts="5mm"
provisional-label-separation="2mm">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>
<fo:inline baseline-shift="super">
<axf:footnote-number-citation ref-id="fn_{#id}"/>
</fo:inline>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates mode="content"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
</fo:footnote-body>
</fo:footnote>
</xsl:template>
</xsl:stylesheet>
These changes generate the footnote the first time that the footnote is used and just generate the number for subsequent times:
<xsl:key name="fn" match="fn[exists(key('footnote', #id))]" use="#id" />
<xsl:key name="fn-first" match="fn[. is key('fn', #id)[1]]" use="#id" />
<xsl:key name="footnote" match="footnote" use="#id" />
<xsl:template match="fn[exists(key('footnote', #id))][. is key('fn-first', #id)]"
mode="content"
priority="7">
<xsl:apply-templates select="key('footnote', #id)"
mode="content">
<xsl:with-param name="number" select="count(preceding::fn[. is key('fn-first', #id)]) + 1"></xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="fn[exists(key('footnote', #id))][not(. is key('fn-first', #id))]"
mode="content"
priority="7">
<fo:inline baseline-shift="super">
<xsl:value-of select="count(key('fn-first', #id)/preceding::fn[. is key('fn-first', #id)]) + 1"/>
</fo:inline>
</xsl:template>
<xsl:template match="footnote" mode="content" priority="5">
<xsl:param name="number" select="count(preceding-sibling::footnote) + 1" as="xs:integer" />
<fo:footnote xsl:use-attribute-sets="fnt.footnote">
<fo:inline baseline-shift="super">
<xsl:value-of select="$number" />
</fo:inline>
<fo:footnote-body space-after="1mm">
<fo:list-block provisional-distance-between-starts="5mm"
provisional-label-separation="2mm">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>
<fo:inline baseline-shift="super">
<xsl:value-of select="$number" />
</fo:inline>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates mode="content" />
</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
</fo:footnote-body>
</fo:footnote>
</xsl:template>
You could tidy it up a bit more by, e.g., making a function that returns the count() value for a fn, but this should get you going.
See my other answer for how you can use both axf:suppress-duplicate-footnote and axf:footnote-number so duplicates are suppressed only when the duplicates are on the same page.
The duplicate footnotes also had duplicate IDs. The error from the non-unique IDs was getting in the way of the axf:suppress-duplicate-footnote processing.
If you're not making links to the footnotes, generate a unique ID for each footnote based on the fn that refers to it:
<xsl:template match="fn[exists(key('footnote', #id))]" mode="content" priority="7">
<!--+ fn link
|
| basic fn (inline) link template.
|
+-->
<xsl:apply-templates select="key('footnote', #id)" mode="content">
<xsl:with-param name="id" select="generate-id()" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="footnote" mode="content" priority="5">
<xsl:param name="id" />
<!--+ footnote
|
| basic footnote template.
|
+-->
<fo:footnote xsl:use-attribute-sets="fnt.footnote" axf:suppress-duplicate-footnote="true">
<fo:inline baseline-shift="super">
<axf:footnote-number id="{$id}" />
</fo:inline>
<fo:footnote-body space-after="1mm">
<fo:list-block provisional-distance-between-starts="5mm"
provisional-label-separation="2mm">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>
<fo:inline baseline-shift="super">
<axf:footnote-number-citation ref-id="{$id}" />
</fo:inline>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates mode="content" />
</fo:block>
</fo:list-item-body>
</fo:list-item>
</fo:list-block>
</fo:footnote-body>
</fo:footnote>
</xsl:template>
Related
Via xsl:for-each-group I group my data with a property pagemaster. For this group I assign the page-sequence in the attribute pagemaster. Then the template is called for each element in this group.
Now to my question: is it somehow possible that I leave the current page-sequence in the for-each loop to insert another page-sequence and then continue with the previous one?
As an example, let's assume that all elements in the group should be rendered on blue pages, but if an element has a certain attribute, a red page will be inserted at this place.
My code section looks like this:
.
<!-- master-set defined here -->
.
</fo:layout-master-set>
<xsl:for-each-group select=".//reportelements/*[pagemaster != '']" group-adjacent="pagemaster">
<fo:page-sequence master-reference="{current-grouping-key()}">
<!-- Static-Content per pagemaster Group -->
<xsl:call-template name="STATIC-CONTENT">
<xsl:with-param name="pageMaster" select="current-grouping-key()" />
</xsl:call-template>
<fo:flow flow-name="xsl-region-body">
<xsl:for-each select="current-group()">
<!-- Here, for example, i would like to check if the current element (.)
is from type "section" and the attribute "hastoc" is true.
If yes the current page sequence should be interrupted and a new page-sequence
should be inserted on which the table of contents is rendered. -->
<xsl:apply-templates select="."/>
</xsl:for-each>
</fo:flow>
</fo:page-sequence>
</xsl:for-each-group>
</fo:root>
</xsl:template>
<xsl:template name="STATIC-CONTENT">
<xsl:param name="pageMaster" />
<xsl:if test="$pageMaster = 'TITLEPAGE'">
<fo:static-content flow-name="xsl-region-after">
<fo:block text-align="right">
<fo:external-graphic src="url(file:C\Logo.pdf)" content-width="6cm" />
</fo:block>
</fo:static-content>
</xsl:if>
</xsl:template>
Xml Code looks like
<?xml version="1.0" encoding="utf-8"?>
<root>
<report>
<layout>report.xsl</layout>
<namecontent>Report</namecontent>
<reportelements>
<section>
<layout>section_normal</layout>
<pagemaster></pagemaster>
<titlecontent>Vorspann</titlecontent>
<hastoc>false</hastoc>
<reportelements>
<picture>
<layout>picture_title</layout>
<pagemaster>TITLEPAGE</pagemaster>
<titlecontent>Titelpicture</titlecontent>
<reportelements />
<path>files\Titelpicture213124.Jpeg</path>
</picture>
<section>
<layout>section_leader.xsl</layout>
<pagemaster>DIN-A4-HEADER-ODD-EVEN</pagemaster>
<titlecontent>Profil</titlecontent>
<hastoc>true</hastoc>
<reportelements>
<paragraph>
<layout>paragraph_leader.xsl</layout>
<pagemaster>DIN-A4-HEADER-ODD-EVEN</pagemaster>
<titlecontent>p1</titlecontent>
<reportelements />
<textcontent>paragraph_leader 1 text</textcontent>
</paragraph>
<paragraph>
<layout>paragraph_leader.xsl</layout>
<pagemaster>DIN-A4-HEADER-ODD-EVEN</pagemaster>
<titlecontent>p2</titlecontent>
<reportelements />
<textcontent>paragraph_leader 2 text</textcontent>
</paragraph>
.
.
.
.
I am using the Apache Formatting Object Processor 2.3
I have created index page using XSLT code. The contents name are shown to index page correctly but i want to map contents according to page number for specific title.
I am getting title with their description So I have named that block as id="TOC" and given as ref-id=”TOC” but the page number is not reflecting in my title.
Title:- Title names present in Index page.
Summary:- Title content associated with page.
The below is my XSLT-2.0 sample code:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="content_name">
<fo:block space-after="7pt" space-after.conditionality="retain" line-height="1.147" font-family="Calibri" font-size="15pt" font-weight="bold" language="FR">
<fo:inline>
<fo:leader leader-length="0pt" />
<xsl:value-of select="title"/>
<fo:page-number-citation ref-id="TOC"/>
</fo:inline>
</fo:block>
</xsl:template>
<xsl:template match="pro_list">
<fo:block space-after="15pt" space-after.conditionality="retain" line-height="1.147" font-family="Calibri" font-size="15pt" font-weight="bold" text-decoration="underline" language="FR">
<fo:inline>
<fo:leader leader-length="0pt" />
<xsl:value-of select="title" id="TOC"/>
</fo:inline>
</fo:block>
<fo:block space-after="8pt" space-after.conditionality="retain" line-height="1.147" font-family="Calibri" font-size="15pt" language="FR">
<fo:inline>
<fo:leader leader-length="0pt"/>
<xsl:value-of select="summary" disable-output-escaping="yes" />
</fo:inline>
</fo:block>
</xsl:template>
</xsl:stylesheet>
This is the output:
Contents
Title1 page no.
Title2 page no.
Title3 page no.
Suppose title1 content is associated with page2 & similar for title2-3 & title3-4, then output looks like as follows
Contents
Title1 2
Tilte2 3
Title3 4
Is there any syntax or predefined function available to do index mapping?
I have this piece of code, modified from the DITA-OT original distribution:
<xsl:template match="*[contains(#class, ' topic/topic ')]" mode="in-this-section-chapter-list">
<fo:block margin-left="6em">
<fo:block>
<xsl:call-template name="insertVariable">
<xsl:with-param name="theVariableID" select="'Chapter with number'"/>
<xsl:with-param name="theParameters">
<number>
<fo:inline>
<xsl:apply-templates select="key('map-id', #id)[1]"
mode="topicTitleNumber"/>
</fo:inline>
</number>
</xsl:with-param>
</xsl:call-template>
</fo:block>
</fo:block>
</xsl:template>
I am trying to only execute/print this mini-toc, when this is a Part that has Chapters as child nodes (see below), but not when it is only a Part without any Chapters, in a book like this:
<?xml version="1.0" encoding="utf-8"?>
<bookmap>
<part>
<chapter/>
<chapter/>
<chapter/>
</part>
<part/>
<part/>
<part/>
<part/>
<appendix/>
</bookmap>
So in this case, only the first <part> would execute/print this.
I thought that passing the value from <xsl:apply-templates select="key('map-id', #id)[1]" mode="topicTitleNumber"/> as text, would allow me to add an if that basically will test for a value that is not empty, thus executing this. But it has not worked.
I came up with something like this, which is not valid:
<xsl:template match="*[contains(#class, ' topic/topic ')]" mode="in-this-section-chapter-list">
<xsl:with-param name="value-number">
<xsl:apply-templates select="key('map-id', #id)[1]"
mode="topicTitleNumber"/>
</xsl:with-param>
<xsl:if test="$value-number!=''">
<fo:block margin-left="6em">
<fo:block>
<xsl:call-template name="insertVariable">
<xsl:with-param name="theVariableID" select="'Chapter with number'"/>
<xsl:with-param name="theParameters">
<number>
<fo:inline>
<xsl:apply-templates select="key('map-id', #id)[1]"
mode="topicTitleNumber"/>
</fo:inline>
</number>
</xsl:with-param>
</xsl:call-template>
</fo:block>
</fo:block>
</xsl:if>
</xsl:template>
For the template to match only part that contain chapter, change match="*[contains(#class, ' topic/topic ')]" to match="part[chapter][contains(#class, ' topic/topic ')]".
You might no longer need the [contains(#class, ' topic/topic ')] if the predicate is going to be true for every part that you're interested in. And you really don't want it if it's going to be false for any of the part that you're interested in.
You may also need to add an OR so that you pick up chapter if you want the minitoc at the chapter level.
Below is my xml file.
<xml>
<top>
<main>
<firstname>John</firstname>
<lastname>John</lastname>
<table></table>
<chapter>
<firstname>Alex</firstname>
<lastname>Robert</lastname>
<p>Sample text chap</p>
<figure name="f1.svg"></figure>
<chapter>
<firstname>Rebec</firstname>
<lastname></lastname>
<p>Sample text</p>
<figure name="f2.svg"></figure>
</chapter>
</chapter>
</main>
</top>
</xml>
Desired output:
<bold>John
table
<bold>Robert
Sample text chap
f1.svg
<bold> Rebec
Sample text
f2.svg
Explaination: I have written an xslt to do this. I need to fetch the xml nodes dynamically. I cannot write: xsl:apply-templates select='main/lastname'. Because my xml format could change anytime.
I have tried a logic to first fetch all the xml nodes using '$root/*'. Then if 'table' element is encountered, i use xsl:apply-templates select='current()[name() = 'TABLE']' and perform table creation operations.
This works fine. I get the desired output but my figure elements only displays f1.svg at every place in the output. f2.svg is not shown.
And how do I match only 'lastname' and make it bold?
I want to make the code as generic/modular as possible so that it loops through all the elements of the xml tree and does some formatting on the specific nodes.
Below is a recursive xslt. With this my data is getting repeated. I am writing recursive template because xslt is not sequential.
XSLT:
<xsl:call-template name="FetchNodes">
<xsl:with-param name="endIndex" select="$NumberOfNodes" />
<xsl:with-param name="startIndex" select="1" />
<xsl:with-param name="context" select="$root/*" />
</xsl:call-template>
<xsl:template name="FetchNodes">
<xsl:param name="endIndex" />
<xsl:param name="startIndex" />
<xsl:param name="context" />
<xsl:if test="$startIndex <= $endIndex">
<xsl:if test="$context[$startIndex][name() = 'table']"">
<xsl:apply-templates select="$context[$startIndex][name() = 'table']"" mode="table" />
</xsl:if>
<xsl:call-template name="FetchNodes">
<xsl:with-param name="endIndex" select="$endIndex" />
<xsl:with-param name="startIndex" select="$startIndex + 1"/>
<xsl:with-param name="context" select="$context" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="node()" mode="table">
<xsl:value-of select="node()" />
</xsl:template>
With the above xslt, something is incorrect in the xpath of apply templates. Output is not proper.
I want XSL FO output.
Can anybody suggest something?
The problem it displaying "f1.svg" instead of "f2.svg" is because of this line
<xsl:variable name="ImageName">
<xsl:value-of select="$root/*/chapter/figure/#name" />
</xsl:variable>
You are already positioned on a figure at this point, so you only need to use a relative xpath expression here. The one you are currently using is an absolute path and so will always return the first #name attribute regardless of your context. It should look this this
<xsl:variable name="ImageName">
<xsl:value-of select="#name" />
</xsl:variable>
Or better still, like this
<xsl:variable name="ImageName" select="#name" />
Having said, the code is in a template that is trying to match an element a FIGURE element, which does not exist in the XML you have shown us. You can actually simplify the template match to this, for example
<xsl:template match="figure" mode="figure">
As for making things bold, you can just add the font-weight attribute to any block you want to make bold. Something like this:
<xsl:choose>
<xsl:when test="self::lastname">
<fo:inline font-weight="bold"><xsl:value-of select="text()" /></fo:inline>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="text()" />
</xsl:otherwise>
</xsl:choose>
EDIT: Having said all that, you may not be taking the correct approach to the problem. It may be better to use template matching, taking advantage of XSLT's built-in template to navigate over the document. Essentially, just write a template for each element you want to match, and generate the output, and then carry on matching its children.
For example, to turn a chapter into an fo:block do this
<xsl:template match="chapter">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
To output the firstname in bold, do this
<xsl:template match="firstname">
<fo:inline font-weight="bold">
<xsl:value-of select="text()"/>
</fo:inline>
</xsl:template>
To turn a figure into an image, do this (Note the use of Attribute Value Templates here, the curly braces indicate an expression to be evaluated, not output literally)
<xsl:template match="figure">
<fo:block>
<fo:external-graphic src="../resources/{#name}" content-height="60%" scaling="uniform" padding-left="2cm"/>
</fo:block>
</xsl:template>
Try this XSLT as a starting point, and build on it
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="main">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="chapter">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
<xsl:template match="firstname">
<fo:inline font-weight="bold">
<xsl:value-of select="text()"/>
</fo:inline>
</xsl:template>
<xsl:template match="lastname"/>
<xsl:template match="figure">
<fo:block>
<fo:external-graphic src="../resources/{#name}" content-height="60%" scaling="uniform" padding-left="2cm"/>
</fo:block>
</xsl:template>
</xsl:stylesheet>
I am using a program to generate a report. The program uses an XSL file to generate a PDF report. I am trying to create a custom XSL file.
In my example, I am trying to only generate a report for items that are 3.5" Floppy OR 5.25" Floppy (separately). In addition to this, I am trying to fit the results in two column per index card - for printing.
I'm not an XSL expert, but I've done a research, and found several possible solutions for what I'm trying to achieve (mainly this question) however the final results are always not what I want them to be - I may have a wrong concept of XSL parts, and I'd appreciate any input/pointers.
Here is a part from the XML:
?xml version="1.0" encoding="UTF-8" ?>
<catalog-objects xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="temp.xsd">
<software-item>
<item>Software</item>
<media-types>
<storage-medium>
<name>5.25" Floppy</name>
</storage-medium>
</media-types>
<title>Title 1</title>
</software-item>
<software-item>
<item>Software</item>
<media-types>
<storage-medium>
<name>3.5" Floppy</name>
</storage-medium>
</media-types>
<title>Title 2</title>
</software-item>
<software-item>
<item>Software</item>
<media-types>
<storage-medium>
<name>3.5" Floppy</name>
</storage-medium>
<storage-medium>
<name>5.25" Floppy</name>
</storage-medium>
</media-types>
<title>Title 3</title>
</software-item>
<software-item>
<item>Software</item>
<media-types>
<storage-medium>
<name>CD-Rom</name>
</storage-medium>
</media-types>
<title>Title 4</title>
</software-item>
Here is a part from the XSL I created:
<?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:import href="../../_stylesheets/pdf_desert.xsl" />
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes" />
<xsl:param name="versionParam" select="'1.0'" />
<xsl:template match="/">
<xsl:param name="size" select="count(catalog-objects/software-item)"/>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="Index Card 4X6"
page-height="4in" page-width="6in" margin-top="4mm"
margin-bottom=".65in" margin-left="4mm" margin-right="4mm">
<fo:region-body />
<fo:region-after />
</fo:simple-page-master>
</fo:layout-master-set>
<xsl:variable name="individualFloppies" select="catalog-objects/software-item[(contains(media-types, '5.25') and not(contains(media-types, '3.5') or contains(media-types, 'ROM') or contains(media-types, 'Disc') or contains(media-types, 'CD') or contains(media-types, 'DVD') or contains(media-types, 'ray'))) or (contains(media-types, '3.5') and not(contains(media-types, '5.25') or contains(media-types, 'ROM') or contains(media-types, 'Disc') or contains(media-types, 'CD') or contains(media-types, 'DVD') or contains(media-types, 'ray')))]" />
<xsl:param name="size" select="$individualFloppies"/>
<xsl:for-each select="$individualFloppies[ceiling($size div 2) >= position()]">
<fo:page-sequence master-reference="Index Card 4X6">
<fo:static-content flow-name="xsl-region-after">
<fo:block font-size="{$fontSize}">
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="{$fontSize}">
<fo:table table-layout="fixed" width="100%" border-collapse="collapse">
<fo:table-column column-width="45%" />
<fo:table-column column-width="45%" />
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block text-align="right" font-size="8"><fo:inline font-weight="bold">ID </fo:inline><xsl:value-of select='format-number(archive-id, "000000")' /></fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block text-align="right" font-size="8"><fo:inline font-weight="bold">ID </fo:inline><xsl:value-of select='format-number(following::software-item[ceiling($size div 2)]/archive-id, "000000")' /></fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell border-bottom="1px solid #000000">
<fo:block text-align="center" padding-top="0.2in" font-size="12" font-weight="bold">
<xsl:value-of select="title" />
</fo:block>
</fo:table-cell>
<fo:table-cell border-bottom="1px solid #000000">
<fo:block text-align="center" padding-top="0.2in" font-size="12" font-weight="bold">
<xsl:value-of select="following::software-item[ceiling($size div 2)]/title" />
</fo:block>
</fo:table-cell>
</fo:table-row>
The PDF report that is generated by the program is wrong because I also get cells with titles that do not match the filter. Also, sometimes at least one item title is not shown.
I tried "reverse engineering" to check whether my variable ($individualFloppies) filter isn't right, but when not using the two column approach I get good results however each in its own row.
It feels as if the following:: is causing the problem but it's just a guess.
I also tried following-sibling::, position() mod 2 = 1 as well as minimizing the filter I have.
If anyone can shed some light and tell me how far I am to what I am trying to achieve and where I am wrong I'd appreciate it very much.
As a first time poster here, I hope I provided all the important information.
EDIT:
I wasn't sure how to attach here the PDF files of the desired and the current output so I'll just ASCII it:
From the XML above, the desired output should only be one page:
╔════════════╤════════════╗
║ Title 1 │ Title 2 ║
╠════════════╪════════════╣
║ │ ║
║ │ ║
║ │ ║
╚════════════╧════════════╝
What I get after generating the report are two pages:
PAGE 1:
╔════════════╤════════════╗
║ Title 1 │ Title 3 ║
╠════════════╪════════════╣
║ │ ║
║ │ ║
║ │ ║
╚════════════╧════════════╝
PAGE 2:
╔════════════╤════════════╗
║ Title 2 │ Title 4 ║
╠════════════╪════════════╣
║ │ ║
║ │ ║
║ │ ║
╚════════════╧════════════╝
To put the logic in writing:
Since 'Title 1' is only '5.25" Floppy' and 'Title 2' is only '3.5" Floppy' they are the only two that should show up.
'Title 3' is '5.25" Floppy' but also is '3.5" Floppy' so it shouldn't show.
'Title 4' is a 'CD-Rom' so it shouldn't show as a column as well.
Writing this makes me realize that the filter I am using isn't working - odd considering I am using some similar filter on some different aspect and it does work.
I hope these edits are what was expected as "examples" and they clarify the issue more.
AFAICT, the problem here is with the expression:
<xsl:value-of select="following::software-item[ceiling($size div 2)]/title" />
Although you are in the context of looping over the filtered variable, the following:: axis is evaluated in the context of the source document. Here's a small stylesheet that demonstrates the problem in isolation as well as a possible solution:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="individualFloppies" select="catalog-objects/software-item[(contains(media-types, '5.25') and not(contains(media-types, '3.5') or contains(media-types, 'ROM') or contains(media-types, 'Disc') or contains(media-types, 'CD') or contains(media-types, 'DVD') or contains(media-types, 'ray'))) or (contains(media-types, '3.5') and not(contains(media-types, '5.25') or contains(media-types, 'ROM') or contains(media-types, 'Disc') or contains(media-types, 'CD') or contains(media-types, 'DVD') or contains(media-types, 'ray')))]" />
<out>
<wrong>
<xsl:for-each select="$individualFloppies">
<pair>
<left><xsl:value-of select="title" /></left>
<right><xsl:value-of select="following::software-item[1]/title"/></right>
</pair>
</xsl:for-each>
</wrong>
<right>
<xsl:for-each select="$individualFloppies">
<xsl:variable name="pos" select="position()" />
<pair>
<left><xsl:value-of select="title" /></left>
<right><xsl:value-of select="$individualFloppies[$pos+1]/title"/></right>
</pair>
</xsl:for-each>
</right>
</out>
</xsl:template>
</xsl:stylesheet>
With the help of michael.hor257k (thanks again!) I managed to add and change the necessary lines of code so it'll generate the report I was aiming for.
Here is the updated code (beginning from where the first change is applied):
<xsl:variable name="individualFloppies" select="catalog-objects/software-item[normalize-space(media-types)='3.5" Floppy' or normalize-space(media-types)='5.25" Floppy']" />
<xsl:param name="size" select="$individualFloppies"/>
<xsl:for-each select="$individualFloppies">
<xsl:variable name="pos" select="position()" />
<xsl:if test="position() mod 2 = 1">
<fo:page-sequence master-reference="Index Card 4X6">
<fo:static-content flow-name="xsl-region-after">
<fo:block font-size="{$fontSize}">
</fo:block>
</fo:static-content>
<!--Table Begins-->
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="{$fontSize}">
<fo:table table-layout="fixed" width="100%" border-collapse="collapse">
<fo:table-column column-width="2.5%" />
<fo:table-column column-width="45%" />
<fo:table-column column-width="2.5%" />
<fo:table-column column-width="2.5%" />
<fo:table-column column-width="45%" />
<fo:table-column column-width="2.5%" />
<fo:table-body>
<fo:table-row>
<fo:table-cell number-columns-spanned="3">
<fo:block text-align="right" font-size="8"><fo:inline font-weight="bold">ID </fo:inline><xsl:value-of select='format-number(archive-id, "000000")' /></fo:block>
</fo:table-cell>
<xsl:choose>
<xsl:when test="position() != last()">
<fo:table-cell number-columns-spanned="3">
<fo:block text-align="right" font-size="8"><fo:inline font-weight="bold">ID </fo:inline><xsl:value-of select='format-number($individualFloppies[$pos+1]/archive-id, "000000")' /></fo:block>
</fo:table-cell>
</xsl:when>
<xsl:otherwise>
<fo:table-cell number-columns-spanned="3"><fo:block></fo:block></fo:table-cell>
</xsl:otherwise>
</xsl:choose>
</fo:table-row>
<fo:table-row>
<fo:table-cell><fo:block></fo:block></fo:table-cell>
<fo:table-cell border-bottom="1px solid #000000">
<fo:block text-align="center" padding-top="0.2in" font-size="12" font-weight="bold">
<xsl:value-of select="title" />
</fo:block>
</fo:table-cell>
<fo:table-cell><fo:block></fo:block></fo:table-cell>
<fo:table-cell><fo:block></fo:block></fo:table-cell>
<xsl:choose>
<xsl:when test="position() != last()">
<fo:table-cell border-bottom="1px solid #000000">
<fo:block text-align="center" padding-top="0.2in" font-size="12" font-weight="bold">
<xsl:value-of select="$individualFloppies[$pos+1]/title" />
</fo:block>
</fo:table-cell>
</xsl:when>
<xsl:otherwise>
<fo:table-cell><fo:block></fo:block></fo:table-cell>
</xsl:otherwise>
</xsl:choose>
<fo:table-cell><fo:block></fo:block></fo:table-cell>
</fo:table-row>
Pointing out the updated lines:
Line 1: Cleaner and, I believe, better way to filter the data into the variable.
Lines 3-4: Implementing first part of michael.hor257k example
Line 5: Make the loop work only on the odd nodes (not sure my terminology is correct)
Lines 26-35/46-57: Implement the second part from michael.hor257k' example as well as check if the current position is the last one.