Can you apply a stylesheet on grouping-separator in XSL? - xslt

In my template, I have defined a decimal format element, that later is used to format some of the numbers coming from the database.
It looks as below:
<xsl:decimal-format name="M" decimal-separator="," grouping-separator=" " infinity="-" minus-sign="-" NaN="-" percent="%" zero-digit="0" digit="#" pattern-separator=";" />
<fo:block font-family="Arial">
<xsl:value-of select="format-number(254768,'## ### ##0.00$','M')"/>
</fo:block>
</xsl:template>
With the above template, I will get the following result: 2 547.68$ .
The <fo:block> element has the same font-family, but it can be set as Regular, or as Bold(font-weight="bold"). When the font is Bold, the space between number 2 and number 5 will be higher, than the space between the same numbers when the font is Regular. I was looking for a way to decrease the space when font-weight is bold.
Is there any way I can apply a stylesheet and manage that space?
Thank you!

Related

Apache FOP: How to hide table-header from the first page only?

I have a document generated using Apache FOP with a multi-pages dynamic table that has a fo:table-header with the sum of items from the previous page using fo:marker and fo:retrieve-table-marker.
<fo:table-header>
<fo:table-row>
<--! column title cells here -->
</fo:table-row>
<fo:table-row>
<fo:table-cell number-columns-spanned="4">
<fo:block>Übertrag</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<fo:inline>
<fo:retrieve-table-marker retrieve-class-name="totalsMarkerHeader"
retrieve-position-within-table="last-ending-within-page"
retrieve-boundary-within-table="table"/>
</fo:inline>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:for-each select="items/item">
<fo:table-row page-break-inside="avoid">
<--! data table cells here -->
<fo:block>
<fo:marker marker-class-name="totalsMarkerHeader">
<xsl:value-of select="format-number(sum(preceding::total_price),'€#,##0.00')"/>
</fo:marker>
</fo:block>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
This works fine, except that on the first page this row is useless, I would like to remove it from the first page and have it on every other page of the document then.
What I am looking for is an option exactly opposite to the "omit-header-at-break" property of the fo:table.
I came across the following options of different rendering engines:
fpc: table-omit-header-at-start="true"
rx: table-omit-initial-header
... but couldn't find something that works with apache fop.
Is there a workaround to do something similar with Apache FOP and the standard XSL-FO?
I also tried to use a conditional visibility for the sum row in the header:
<xsl:if test="position() > 1">
<fo:table-row>
...
</fo:table-row>
</xsl:if>
Unfortunately it doesn't seem like the header condition is evaluated on every page, but is rather done once on the first page making the row invisible on all pages (not just the first page as I would have expected).
If the section of your document with this table can be isolated into a single page-sequence then:
1) Setup a page sequence with a different first page (so use first and any)
2) In the page template for all pages but the first, create a matching simple one row table in the region before, set to the very bottom so it lands on top of the table in your body. Carefully planned, you can make the little table in the header look like it is a "table-header" even though it is in the page header.
3) Obviously do not put any header on the first page and of course not on the table in the body unless you want to, you can put something completely different here because it would be the region-before of the first page.
4) The you can use regular markers to keep the running total and pull that marker into your table in the header on latter pages.
Add an empty fo:marker that will be picked up by the fo:retrieve-table-marker only on the first page.

My xsl-fo stylesheet don't add my page number prefix as expected

I'm trying to change the way the index page works by adding to it a number present in the xml. so in theory this is supposed to be made out of the box, but for some reason the output doesn't have my page-number prefix.
for example, if the node somethingElse has the value, 57 and is on the page 13 I want to have 57.13 displayed on the index but only 13 gets displayed.
I tried to change value-of/inline to a block conataining only a word test, but even that doesn't seem to work. So I can only assume that I'm not using index-page-number-prefix correctly...
What am I doing wrong ?
<fo:block>
<fo:inline font-weight="normal">
<fo:leader leader-pattern="dots"/>
<fo:index-page-citation-list>
<fo:index-key-reference ref-index-key="{.};{../title};;" font-weight="bold">
<fo:index-page-number-prefix>
<fo:inline>
<xsl:value-of select="ancestor::something/SomethigElse"/>.
</fo:inline>
</fo:index-page-number-prefix>
</fo:index-key-reference>
</fo:index-page-citation-list>
</fo:inline>
</fo:block>
fo:index-page-number-prefix is ignored by RenderX. See http://www.renderx.com/reference.html#XSL11_Support or, more specifically, http://www.renderx.com/reference.html#XSL11_Indexes.

Traverse xml document using xpath and xsl

I am using XSL and XPATH to traverse, read and transform a complex XML file where I have multiple nodes with same names but different values. My sample xml file is below -
<core>
<address>
<postalZipCode>90017</postalZipCode>
<updateSource>xxxxxx</updateSource>
<city>LOS ANGELES</city>
<stateProvince>CA</stateProvince>
<type>MAILING</type>
<line1>818 WEST SEVENTH STREET</line1>
</address>
<address>
<postalZipCode>95014</postalZipCode>
<updateSource>xxxxxx</updateSource>
<city>CUPERTINO</city>
<stateProvince>CA</stateProvince>
<type>PRIMARY</type>
<line1>1234 XYZ STREET</line1>
</address>
<memberId>0</memberId>
</core>
When I read the MAILING ADDRESS Line 1 value , the value I am getting is "1234 XYZ STREET" which essentially is the PRIMARY ADDRESS . Here is my xsl file snippet :-
<xsl:template match="core">
<xsl:if test="memberId['0'] and address/type['MAILING']">
<fo:table-row>
<fo:table-cell><fo:block /></fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="data">
<fo:block>Line 1</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="data">
<fo:block><xsl:value-of select="address/line1/text()"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
Could the experts here please suggest if there is any other way possible to force XSL to read the correct value of where address is MAILING, instead of reading the first value it finds ???
if there is any other way possible to force XSL to read the correct
value of where address is MAILING, instead of reading the first value
it finds ???
Your question is rather confusing, because MAILING is the first address in your example - and the snippet you show does not produce the result you say it does.
In any case, to make sure you get data from the MAILING address regardless of its position, change this:
<xsl:value-of select="address/line1/text()"/>
to:
<xsl:value-of select="address[type='MAILING']/line1"/>
To understand how this works, read more about predicates.
The code you have written says "if there is an address with type MAILING, then print the value of address/line1 (whether or not this is in any way related to the address with type MAILING)".
In XSLT 1.0, when xsl:value-of selects more than one node, it displays the value of the first one it finds. In XSLT 2.0 it concatenates the values of all the selected nodes, with a separator that defaults to a single space.
If there's more than one node and you want to select a specific one, then select it with a predicate, e.g. xsl:value-of select="address[#type='MAILING']/line1.

XSL-FO leader wrapping

I have a list of data with a dotted leader separating text aligned to the left and to the right. I'm using the following XSL-FO to achieve this.
<fo:block text-align-last="justify">
<xsl:value-of select="left-text"/>
<fo:leader leader-pattern="dots"/>
<xsl:value-of select="right-text"/>
</fo:block>
Some text on the left............................some text on the right
This works perfectly when the text all fits onto one line. The issue I'm having is correctly handling how the text on the right wraps onto a new line. I have a specific requirement for it to be formatted with the wrapped text staying aligned to the right as below:
Some text on the left.................a long piece of text on the right
that has wrapped
I tried to achieve this with leaders and tables but to no avail. I'm using the Antenna House formatter. Any advice is very welcome.
Thanks for you help.
Use this as inspiration and set your own rules:
<fo:block text-align="justify" text-align-last="right">
<fo:inline>Some text on the left</fo:inline>
<fo:leader leader-pattern="dots" leader-length.minimum="2in" leader-length.optimum="2in" leader-length.maximum="3in"/>
<fo:inline>a long piece of text on the right that has wrapped</fo:inline>
</fo:block>
<fo:block text-align="justify" text-align-last="right">
<fo:inline>Some text</fo:inline>
<fo:leader leader-pattern="dots" leader-length.minimum="2in" leader-length.optimum="2in" leader-length.maximum="3in"/>
<fo:inline>a long piece of text on the right that has wrapped and is even longer</fo:inline>
</fo:block>
The only things you will not be able to stop is a right hand line so long that it comes underneath the dots, but you have not specified that as a requirement. If that is, I am afraid there is no solution for that. Also if a line is too short, it would be right aligned. You have to use the min/max values to only force a wrap.
If you know the font size you could count the characters in the left/right elements and then call your template or this sample depending on the total characters.
And for the count, you can do something like this template where the "50" characters you can adjust with the leader-length to get the correct results.
<xsl:template name="processitem">
<xsl:choose>
<xsl:when test="string-length(left) + string-length(right) > 50">
<fo:block text-align="justify" text-align-last="right">
<fo:inline><xsl:value-of select="left"/></fo:inline>
<fo:leader leader-pattern="dots" leader-length.minimum="2in" leader-length.optimum="2in" leader-length.maximum="4in"/>
<fo:inline><xsl:value-of select="right"/></fo:inline>
</fo:block>
</xsl:when>
<xsl:otherwise>
<fo:block text-align-last="justify">
<fo:inline><xsl:value-of select="left"/></fo:inline>
<fo:leader leader-pattern="dots"/>
<fo:inline><xsl:value-of select="right"/></fo:inline>
</fo:block>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
With some sample data, I got this to render:
You can use an fo:inline-container (https://www.w3.org/TR/xsl11/#fo_inline-container) and the max-width property (https://www.w3.org/TR/xsl11/#max-width) to limit the width of any long text on the right.
This example uses the axf:text-align-first="justify" extension (see https://www.antennahouse.com/product/ahf66/ahf-ext.html#axf.text-align-first) to justify the first line. You could instead use the axf:leader-expansion="force" extension (see https://www.antennahouse.com/product/ahf66/ahf-ext.html#axf.leader-expansion). Without either of those, I think that your only other alternative is to guesstimate the leader-length.optimum of the second fo:leader.
Note that the example below has no significant white-space characters between the two fo:leader. This avoids a gap between the two leaders when they are formatted.
<fo:block text-align="justify">
<fo:inline>Some text</fo:inline><fo:leader
leader-pattern="dots" leader-length.optimum="100%"
leader-alignment="end"
/><fo:inline-container
max-width="1.5in" text-align="right"
axf:text-align-first="justify" >
<fo:block><fo:leader leader-pattern="dots"
leader-length.minimum="0" />a long piece of text on the right that has wrapped
and is even longer</fo:block>
</fo:inline-container>
</fo:block>

How to have different formatting under same fo:block in XSL stylesheet?

I have a stylesheet as follows(snippet):
<fo:block xsl:use-attribute-sets="header" text-align-last ="justify">
<xsl:value-of xsl:use-attribute-sets="branding" select="$pTitle"/>
<fo:leader leader-pattern = "space" />
<xsl:value-of select="$vNamer"/>
</fo:block>
this lets me render the heading as such:
title name
------------------------------------------
however, I want the "title" to have a different font size(and bolded). how do I apply attributes to "title" only?
You can use fo:inline to wrap the part you want to apply attributes to.
From the spec:
Common Usage:
The fo:inline formatting object is commonly used for formatting a
portion of text with a background or enclosing it in a border.