I am trying to display the current date, inside a repeating context, where my element is outside the repeating context.
Sample XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<AllLines>
<Versions>
<field1>V1.0</field1>
<field2>A1.0</field2>
</Versions>
<Versions>
<field1>V2.0</field1>
<field2>A2.0</field2>
</Versions>
<Versions>
<field1>V3.0</field1>
<field2>A3.0</field2>
</Versions>
<Versions>
<field1>V4.0</field1>
<field2>A4.0</field2>
</Versions>
<Versions>
<field1>V5.0</field1>
<field2>A5.0</field2>
</Versions>
</AllLines>
<CurrentLines>
<CurrentLine date="21 Aug">
<field1>X1.0</field1>
<field2>Y1.0</field2>
<field3>Y1.0</field3>
</CurrentLine>
<CurrentLine date="30 Jan">
<field1>X2.0</field1>
<field2>Y2.0</field2>
<field3>Y2.0</field3>
</CurrentLine>
<CurrentLine date="02 Feb">
<field1>X3.0</field1>
<field2>Y3.0</field2>
<field3>Y3.0</field3>
</CurrentLine>
<CurrentLine date="21 Aug">
<field1>X4.0</field1>
<field2>Y4.0</field2>
<field3>Y4.0</field3>
</CurrentLine>
<CurrentLine date="03 Jan">
<field1>X5.0</field1>
<field2>Y5.0</field2>
<field3>Y5.0</field3>
</CurrentLine>
</CurrentLines>
</root>
My sample template will look like this:
<xsl:template name="displayDate">
<fo:block>
<xsl:for-each select="/root/AllLines/Versions">
<fo:block>
<xsl:value-of select="field1" />
</fo:block>
<fo:block>
<xsl:value-of select="field2" />
</fo:block>
<fo:block border-bottom="1pt solid black" margin-bottom="4pt">
<xsl:value-of select="/root/CurrentLines/CurrentLine[current()]/#date" />
</fo:block>
</xsl:for-each>
</fo:block>
</xsl:template>
With the above template, I am generating the following output:
V1.0
A1.0
21 Aug
--------
V2.0
A2.0
21 Aug
-------
V3.0
A3.0
21 Aug
------
V4.0
A4.0
21 Aug
------
V5.0
A5.0
21 Aug
The third element in each repeating group, is always going to display the first date attribute, from /root/CurrentLines/CurrentLine.
The expected result will be:
V1.0
A1.0
21 Aug
--------
V2.0
A2.0
30 Jan
-------
V3.0
A3.0
02 Feb
------
V4.0
A4.0
21 Aug
------
V5.0
A5.0
03 Jan
Is there any way I can still keep repeating after Versions and display the current fields, but have the current #date attribute displayed based on the corresponding current CurrentLine element?
Thank you!
Try:
<xsl:for-each select="/root/AllLines/Versions">
<xsl:variable name="i" select="position()" />
<fo:block>
<xsl:value-of select="field1" />
</fo:block>
<fo:block>
<xsl:value-of select="field2" />
</fo:block>
<fo:block border-bottom="1pt solid black" margin-bottom="4pt">
<xsl:value-of select="/root/CurrentLines/CurrentLine[$i]/#date" />
</fo:block>
</xsl:for-each>
Related
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 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>
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.
Looking at the available axes in XSLT I had to find out that there is no sibling axis which would be the union of preceding-sibling and following-sibling. To me this is a little surprising since I already wrote one answer (XSLT issue...CSV issue.?) in which this axis would have been helpful (although I only have about 10 answers so far). Of course, it is obvious that you can always solve the problem by using the union. So this axis is not really required. But it would be very handy every once in a while and like all the other axes IMHO it would make the code more readable and easier to maintain.
Does anybody know why this axis was left out? Is there maybe a non-obvious reason for this?
By the way: I found at least one issue on StackExchange with a warning about a potential performance degrade using the preceding-sibling and following-sibling axes. But I assume this is true for all the axes containing a substantial portion of the XML tree is used in a nested way. So the reason for omission could not have been due to performance.
Since there has been no activity with this question for a while I would like to answer it myself. Picking up one thought in the comments, it is, of course, hard to retrospectively say why the people responsible of the XSLT 1.0 specification omitted the sibling axis.
One of the most conclusive reasons could have been related to the comments by #JLRiche and #MichaelKay: axis are supposed to go into a specific direction with respect to the reference node and it may be difficult to determine what the direction for sibling would be.
In order to investigate this a little further I set up a test XSLT and a test input XML to check how the axes work (see further below) and in particular what the order of the nodes in the axes are. The result was surprising to me:
The preceding-sibling axes does not start at the node closest to the reference node but with node closest to the start of the document.
The following-sibling does start at the reference node.
This would actually allow to define
sibling := preceding-sibling | following-sibling
with the nodes in this set being continuously iterated from the beginning of the document to the end. There would be no "jump".
The suggested alternative
../node except .
also works well and yields the same set in the same ordering. However, looking at an unfamiliar XSLT I would assume that a sibling axis would explain the logic better than using the parent-children construct.
Interestingly, the fact that axes do not start at the node closest to the reference node but at the node closest the beginning of the document also applies to preceding and ancestor so for example ancester::node[1] does not return the parent of the node but the root node.
The original motivation for me to ask the question was related to not having to repeat a lengthy CONDITION imposed on the attributes of the nodes, e.g. I did not want to write
preceding-sibling::node[CONDITION] | following-sibling::node[CONDITION]
However, since the expression above can be rewritten as
(preceding-sibling::node | following-sibling::node)[CONDITION]
the disadvantage of having to use two axes instead of a sibling axis is not as bad as thought. Of course, in XSLT 2.0 this also works for
(../node except .)[CONDITION]
So, to answer my question: I don't think there is a good reason not to define a sibling axis. I guess nobody thought of it. :-)
Test Setup
This XML test input
<?xml version="1.0" encoding="ISO-8859-1"?>
<node id="1">
<node id="2">
<node id="3">
<node id="4"/>
<node id="5"/>
<node id="6"/>
</node>
<node id="7">
<node id="8"/>
<node id="9"/>
<node id="10"/>
</node>
<node id="11">
<node id="12"/>
<node id="13"/>
<node id="14"/>
</node>
</node>
<node id="15">
<node id="16">
<node id="17"/>
<node id="18"/>
<node id="19"/>
</node>
<node id="20">
<node id="21"/>
<node id="22"/>
<node id="23"/>
</node>
<node id="24">
<node id="25"/>
<node id="26"/>
<node id="27"/>
</node>
</node>
<node id="28">
<node id="29">
<node id="30"/>
<node id="31"/>
<node id="32"/>
</node>
<node id="33" value="A">
<node id="34"/>
<node id="35"/>
<node id="36"/>
</node>
<node id="37">
<node id="38"/>
<node id="39"/>
<node id="40"/>
</node>
<node id="41">
<node id="42"/>
<node id="43"/>
<node id="44"/>
</node>
<node id="45" value="A">
<node id="46"/>
<node id="47"/>
<node id="48"/>
</node>
</node>
</node>
using this XSLT 2.0 sheet
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:variable name="id" select="'37'"/>
<xsl:template name="dump">
<xsl:text> </xsl:text>
<xsl:value-of select="#id"/>
</xsl:template>
<xsl:template match="//node[#id = $id]">
<xsl:text>preceding siblings: </xsl:text>
<xsl:for-each select="preceding-sibling::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
following siblings: </xsl:text>
<xsl:for-each select="following-sibling::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
preceding and following siblings: </xsl:text>
<xsl:for-each select="preceding-sibling::node | following-sibling::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
preceding and following siblings with value A: </xsl:text>
<xsl:for-each select="(preceding-sibling::node | following-sibling::node)[#value = 'A']">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
following siblings: </xsl:text>
<xsl:for-each select="following-sibling::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
parent's children: </xsl:text>
<xsl:for-each select="../node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
parent's children except self: </xsl:text>
<xsl:for-each select="../node except .">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
parent's children except self with value A: </xsl:text>
<xsl:for-each select="(../node except .)[#value = 'A']">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
ancestors: </xsl:text>
<xsl:for-each select="ancestor::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
immediate ancestor: </xsl:text>
<xsl:for-each select="(ancestor::node)[1]">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
ancestors or self: </xsl:text>
<xsl:for-each select="ancestor-or-self::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
descendants: </xsl:text>
<xsl:for-each select="descendant::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
descendants or self: </xsl:text>
<xsl:for-each select="descendant-or-self::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
preceding: </xsl:text>
<xsl:for-each select="preceding::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text>
following: </xsl:text>
<xsl:for-each select="following::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
will yield this output
preceding siblings: 29 33
following siblings: 41 45
preceding and following siblings: 29 33 41 45
preceding and following siblings with value A: 33 45
following siblings: 41 45
parent's children: 29 33 37 41 45
parent's children except self: 29 33 41 45
parent's children except self with value A: 33 45
ancestors: 1 28
immediate ancestor: 1
ancestors or self: 1 28 37
descendants: 38 39 40
descendants or self: 37 38 39 40
preceding: 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36
following: 41 42 43 44 45 46 47 48
I am generating a PDF using XSL-FO and XML. In a textbox, the user can enter data like "1", then he presses ENTER, then "2", ENTER, "3", etc. But in the XML and hence in the PDF, the output is "1234567". How can I preserve the line breaks? I already tried white-space-collapse, linefeed-treatment and white-space-treatment but that didn't help.
My XSL looks like:
<xsl:template match="AddCmt">
<fo:block keep-together="always"> Additional Comments
<fo:block-container border-style="solid" height="20mm" width="170mm" space-after="5mm">
<fo:block>
<xsl:attribute name="id">
<xsl:value-of select="../CMT_ID"/>
</xsl:attribute>
<xsl:value-of select="../ANS_CMT"/>
</fo:block>
</fo:block-container>
</fo:block>
</xsl:template>
When I enter the following:
hello
medhavi
saraswat
This is the XML I get:
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type='text/xsl' href='e:\tmm-09.3\src\pmod\WorkOrder.xsl'?>
<Root>
<WorkOrders>
<Detail>Id="ANS_436_FLD_1" Label="qq">qq</Detail>
<Ans Checked="0" Id="ANS_436_FLD_2" Label="ww">ww</Ans>
<ID>ANS_436_FLD</ID>
<ANS_FLD>0|0</ANS_FLD>
<CMT_ID>ANS_436_CMT</CMT_ID>
<ANS_CMT>hello medhavi saraswat</ANS_CMT>
<Warning>
<Line>warning 11</Line>
<Line>22</Line>
<Line>33</Line>
<Line>44</Line>
<Line></Line>
<Line>66</Line>
<Line>77</Line>
<Line></Line>
</Warning>
It should work with the following xml (you should add all the attributes):
<xsl:template match="AddCmt">
<fo:block keep-together="always"> Additional Comments
<fo:block-container border-style="solid" height="20mm" width="170mm" space-after="5mm">
<fo:block wrap-option="wrap" linefeed-treatment="preserve" white-space-collapse="false" white-space-treatment="preserve">
<xsl:attribute name="id">
<xsl:value-of select="../CMT_ID"/>
</xsl:attribute>
<xsl:value-of select="../ANS_CMT"/>
</fo:block>
</fo:block-container>
</fo:block>
</xsl:template>
But as I mentioned in the comments, if your XML already has no linebreaks, there's no way your PDF will. You mentioned in your question there are no linebreaks in your XML, hence no linebreaks in the PDF.
Try checking out why there are no linebreaks in the XML. If you can provide any more information (a piece of your XML, the code you use to construct the XML, ...), please edit your answer and add the information.