0

I am trying to implement FOP to output a PDF using XML and XSLT files.

My problem is the following I need to fix the position of words in a line (but not through using tables) for example:

I have the following xml:

 <address>
    <Line1 length="32" noLine="5" col="60" />
    <Line2 length="32" noLine="6" col="60">Mr. John Kane</Line2 >
    <Line3 length="32" noLine="7" col="60">15 Street Springfield</Line3 >
    <Line4 length="32" noLine="8" col="60" />
    <Line5 length="32" noLine="9" col="60" />
    <Line6 length="6" noLine="10" col="60">75009</Line6 >
    <Line7 length="25" noLine="10" col="67">Freesberg</Line7 >
    <Line8 length="25" noLine="11" col="67">Idaho</Line8 >
  </address>
  1. Where the length is the word/sentence length
  2. noLine is the line number
  3. col is the beginning position of the word/sentence in the line

I did the lines but I can't seem to get to insert the word/sentence in the right position (col) in the line.

This is a part from my xslt:

<fo:block font-size="10" font-family="monospace">
<xsl:for-each select="*">
<xsl:variable name="currentNode" select ="name(.)"/>

<xsl:choose>
<xsl:when test="$currentNode = 'address'">
                                                <xsl:for-each select="*">
                                                    <xsl:variable name="length" select ="@length"/>
                                                    <xsl:variable name="noLine" select ="@noLine"/>
                                                    <xsl:variable name="col" select ="@col"/>
                                                    <xsl:variable name="precNoLig" select = "preceding-sibling::*[1]/@noLine"/>
                                                    <xsl:choose>
                                                        <xsl:when test="$precNoLig = $noLine">
                                                            <fo:block font-size="10" font-family="monospace" text-indent="60">
                                                                &#160;<xsl:value-of select="." />
                                                            </fo:block>
                                                        </xsl:when>
                                                        <xsl:otherwise>
                                                            <!--<fo:block font-size="10" font-family="monospace" >-->
                                                                &#x2028;<xsl:value-of select="." />
                                                            <!--</fo:block>-->
                                                        </xsl:otherwise>
                                                    </xsl:choose>
                                                </xsl:for-each>
    </xsl:when>
    </xsl:choose>

    </xsl:for-each>
    </fo:block>

This is the expected output as PDF :

                                         Mr. John Kane
                                         15 Street Springfield


                                         75009 Freesberg
                                               Idaho

Where it has the following positions in the PDF (col):

<-----------------60-------------------->
<-----------------60-------------------->Mr. John Kane
<-----------------60-------------------->15 Street Springfield
<-----------------60-------------------->
<-----------------60-------------------->
<-----------------60-------------------->75009 Freesberg
<-----------------67-------------------------->Idaho

Any help would be appreciated.

Flynn1179
  • 11,925
  • 6
  • 38
  • 74
GingerHead
  • 8,130
  • 15
  • 59
  • 93
  • @DimitreNovatchev It's simple as this: I pass the `xslt` and `xml` files to FOP and it generates the `PDF` for me – GingerHead Aug 31 '12 at 13:37
  • Still there isn't the expected/wanted output from the transformation -- that should be the generated XSL-FO that then is fed to the formatter. Please, add this missing information. – Dimitre Novatchev Aug 31 '12 at 14:17
  • Mike, Sorry, but what is added isn't the output from the XSLT transformation -- it is the output from FOP. Please, provide the wanted output from the XSLT transformation. – Dimitre Novatchev Aug 31 '12 at 14:31
  • @DimitreNovatchev I'm not saying that, I'm just saying: `fix the location of a word in a line in PDF with FOP` – GingerHead Sep 03 '12 at 06:18
  • 1
    @MikeMyers: There's nothing wrong with the question, it makes perfect sense to me. I've got an idea I'd like to try, if I get it working I'll post an answer. – Flynn1179 Sep 03 '12 at 06:23
  • @MykeMierz, Please, do learn to explain a problem. I don't see any requirements **what** an XSLT transformation is expected to produce -- and when asked you didn't seem to know. – Dimitre Novatchev Sep 03 '12 at 14:30
  • 1
    http://dilbert.com/strips/comic/2012-05-17/ – Flynn1179 Sep 03 '12 at 15:03
  • Hahahaha yeah that explains it! – GingerHead Sep 04 '12 at 05:59

1 Answers1

1

It's a little convoluted, but this should work:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:strip-space elements="*" />
  <xsl:output method="text"/>

  <xsl:variable name="sp" select="'                                                                                          '" />

  <xsl:template match="address/*">
    <xsl:variable name="value">
      <xsl:value-of select="." />
      <xsl:if test="following-sibling::*[1]/@noLine = @noLine">
        <xsl:value-of select="$sp" />
      </xsl:if>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="preceding-sibling::*[1]/@noLine = @noLine">
        <xsl:variable name="col" select="preceding-sibling::*[1]/@col + preceding-sibling::*[1]/@length" />
        <xsl:value-of select="concat(substring($sp,1,@col - $col),substring($value,1,@length))" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:if test="preceding-sibling::*"><xsl:text>&#10;</xsl:text></xsl:if>
        <xsl:value-of select="concat(substring($sp,1,@col),substring($value,1,@length))" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

For this transform to work as-is, it's critical that your Line.. elements are in noLine/col order, as it bases how to pad it out on the previous element. If they're out of order it'll get it badly wrong.

The sp variable must contain at least as many spaces as you'll ever need to pad it out to, i.e. the max value of any length or col attribute. This solution doesn't include spaces at the end of a line- it's actually easier to pad out each line with trailing spaces so that it fills the length given, but I assumed it would probably be preferable not to.

I've only tried it with the sample given, if it doesn't work for any other input you've got, let me know and I'll see if I can adapt it.

EDIT: I just noticed that you needed it in PDF format, sorry. I just looked at the output, and didn't notice the format. Hopefully you can adapt this to the format you need (It's actually quite similar to what you'd already tried), but if not, I'd suggest you manually create a PDF that represents your output and add the XML for that PDF to your question.

Flynn1179
  • 11,925
  • 6
  • 38
  • 74
  • Not really, unfortunately. There is a way of writing a template that outputs a given number of spaces, but it would more than double the length of that stylesheet. Taking a substring of a hardcoded string of spaces like this is usually a LOT easier where the maximum length you'll need is known. – Flynn1179 Sep 03 '12 at 08:25
  • It doesn't matter how much it varies, only that it's long enough to cover the maximum that exists anywhere in the source XML. In this context, I'd have thought enough spaces to cover the entire width of a line should be adequate. When I get a chance, I'll add a template that can be called with any arbitrary length, it's generally useful anyway. – Flynn1179 Sep 03 '12 at 08:51