Tuesday Mar 27, 2007

Anatomy of a Template I - Fixed Row Enumeration

The bursting articles are still in process ... I did some work a while back for a training course on the 'anatomy of an invoice template' ... there are some useful 'bits' that I thought you might like to see. 


One of the most requested features on the forum for RTF templates is to show a fixed number of rows per page. Maybe you have pre-printed stationary that can only take a certain number of lines, maybe you have a functional requirement for it. For whatever the reason id the functional folks have given it to you to implement.  Up until now there has been a template floating around that I think I let loose that shows how this can be done for invoices. There is little explanation of whats going on and how it's done. I'll try and make ammends to those of you that may have gotten a little lost but plugged it in anyway and it worked so what the heck.


I have started off small and we'll build this template up into a full invoice format that can run against the standard AR Oracle Report in 11i (RAXINV) ... those of you that are not EBSer's or are not interested in the invoice format, dont worry, you can follow along and apply the same principles to any data set. Here's the features out template is going to have.

1. A fixed number of rows per page,
2. 'Filler' space for lines, because that last page may only have 3 lines but you want to maintain the layout
3. Page totals or 'Continued' in place of a total
4. Last page only content
5. Header and page number resetting as we hit each new invoice in the batch.


For all of the explanations we are going to use the attached XML. Its a full invoice batch, thats multiple invoices having multiple lines.

The Data


Lets start with number 1, for the fixed row enumeration we are only interested in the lines section of the XML, so we can focus on this portion Im going to ignore the rest of the XML. We are only interested in the G_LINES group of the XML structure:

<G_LINES>
 <LINE_NUMBER>1</LINE_NUMBER>
 <LINE_CUSTOMER_TRX_ID>1903</LINE_CUSTOMER_TRX_ID>
 <LINE_CUSTOMER_TRX_LINE_ID>1801</LINE_CUSTOMER_TRX_LINE_ID>
 <LINE_CHILD_INDICATOR>0</LINE_CHILD_INDICATOR>
 <LINE_TYPE>LINE>LINE</LINE_TYPE>
 ...
</G_LINES>
<G_LINES>
 <LINE_NUMBER>2</LINE_NUMBER>
 <LINE_CUSTOMER_TRX_ID>1903</LINE_CUSTOMER_TRX_ID>
 <LINE_CUSTOMER_TRX_LINE_ID>1817</LINE_CUSTOMER_TRX_LINE_ID>
 <LINE_CHILD_INDICATOR>1</LINE_CHILD_INDICATOR>
 <LINE_TYPE>LINE>LINE</LINE_TYPE>
 ...
</G_LINES>


There are obviously a lot more elements and a lot more lines but all we are interested in is, the grouping and the line type for now.


The Template


Now take a look at the template; if you just look at the table and nothing else it all looks pretty normal. We have a for-each, some fields followed by an end for-each ... straightforward stuff right. You'll notice the for-each has a little more going on thou and there's that 'if' condition:

<?for-each:$invLines?>
<?if:position()>=$start and position()<$start+$lpp?> 

I'll come back to these, lets look first at the fields above the table:

LinesPerPageVariable - this does what it says on the can and sets up the number of lines we want to see per page and assigns it to a variable 'lpp'. Now remember native XSL 'variables' are not like other language variables, think of them more as constants.

        <xsl:variable name="lpp" select="number(15)"/>

LinesTreeVariable - this holds not just a single value but a complete tree of values. Word of caution here, if you are going to do this you need to be aware that the XSLT engine is going to load this tree into memory ... so do not load huge trees. In our completed invoice template we will only load the lines tree for each invoice. In this example we are loading all the lines in the XML regardless of invoice ... thats OK thou, our XML is small, just be aware of what are doing here.
We have a variable 'invLines' and we are loading the members of the G_LINES group where the TYPE is equal to 'LINE'. Notice we use an XPATH expression to do this. We also use the 'incontext' command to ensure we are picking up the lines only for the current position i.e. within the current invoice. For this example remember we have no invoice header so we pick up all lines into the tree.

          <xsl:variable xdofo:ctx="incontext" name="invLines" select=".//G_LINES[LINE_TYPE='LINE']"/>

FEinvLines - this is the first loop we need to to go over the G_LINES group we created earlier. Although there is only a single group we need to iterate over it so we can set up a variable to hold the starting line position.
The if statement is checking if the record position we have reached modulizing with the line per page count equals zero i.e. we have reached the first record
 the create a variable (constant) called 'start' and initialize it with '0'.

<?for-each:$invLines?>  
 <?if:(position()-1) mod $lpp=0?>  
   <xsl:variable name="start" xdofo:ctx="incontext" select="position()"/>


Now we get into the table, the first field in their is another for-each but this time we are going to loop over the members of the invLines tree. Notice the use of the '$' to reference the variable.


<?for-each:$invLines?>
 <?if:position()>=$start and position()<$start+$lpp?>

The if statement here is checking that the current record pointer 'position()' is either greater than 'start' ie the first record or less the 'lpp' value we set up earlier. If it is then show the record otherwise not. the rest of the table is standard stuff.

Now we wanted a fixed number of rows per page and the logic above will provide that but of course the template needs to signify the need for a page break after the alloted number of rows have been shown. Looking at the 'Page Break' field:


<xsl:if xdofo:ctx="inblock" test="$start+$lpp<=count($group)">
 <xsl:attribute name="break-before">page</xsl:attribute>
</xsl:if>

We have an 'if' statement wrapped around the page break instruction. This is just like the if in the table, if the specified number of rows has been met then insert a page break.

So thats fixed row enumeration, hope things are a little clearer. Next we'll add in the header for th invoices so we can then ensure we have a fixed layout per page of each invoice. Complete template, data and PDF are here.

Thursday Mar 08, 2007

Addition Not Applicable

[Read More]

Monday Mar 05, 2007

Indenting Lists

[Read More]

Wednesday Feb 28, 2007

En-Gauging Output

[Read More]

Wednesday Feb 21, 2007

More Charts Anyone?

Charts charts charts ... yep XMLP/BIP can do em ... in fact it can do about 30 different types but the Insert Chart dialog of the template builder now only exposes about 6 of them, with a few bells and whistles ... if you want to go further then you have to get coding. I've covered some alternatives for the coding in previous posts but Im now posting what I hope is going to be a useful 'cheat sheet' for some of the tougher chart styles. Again, thanks to another Oracle Consulting star, Kan Nishida who put the samples together you can now quickly grasp how to put together the following chart types:


  • Multi Bar Chart
  • Dual Y Bar Chart
  • Split Dual Bar chart
  • Vertical Bar Stack
  • Line Chart
  • Dual Line Chart
  • Pie chart
  • Pie Ring Chart
  • Multi Pie Charts
  • Area Chart
  • Area Vertical Stack

Some easy ones, some not so easy, Kan has provided some useful hints in the template on whats needed for a specific chart type and of course you can always take a look at the web properties for the dummy chart images to get a better idea. RTF template, XML data and PDF output available here.


Tuesday Feb 20, 2007

Empower your users ...

[Read More]

Thursday Feb 15, 2007

Media Images can cause hair loss

[Read More]

Tuesday Jan 02, 2007

Formatting HTML with Templates

Happy New Year everyone ... back on the horse again, I'll try and stay on this time!

I have had several requests on how to handle HTML formatted XML in their templates, to save you time finding my email and me answering here's the solution. When there is HTML formatted data in the source XML it needs to be converted to the XSLFO format prior to being put into the final document otherwise the raw HTML will be inserted so something like

<B>This is bold text</B>
needs to be converted to its XSLFO equivalent

<fo:inline font-weight="bold">This is bold text</fo:inline>
We can do this reasonably simply but their is one caveat. The HTML must be in the XHTML format i.e. <BR> is not going to work it needs to be <BR></BR> for a new line. So, if you have HTML in your data you'll need to clean it up to get XHTML using something like JTidy or Tidy.  Once you have the cleaned up XHTML you're ready to convert it to the XSLFO equivalent.

To do this, the easiest way is to use a sub template, Im advocating that because you are likely to need to use the functionality across multiple templates. The sub template is going to be written in XSLFO, not the easiest language in the world but I have posted a sample template that handles much of the common HTML for you. Its basically a set of functions that accept the input and convert it if necessary to XSLFO. Take a look at the template and you'll see a series of functions with a similar format:

<xsl:template match="STRONG|B|b">
 <fo:inline font-weight="bold">
  <xsl:apply-templates /> 
 </fo:inline>
</xsl:template>
The first line is looking for 'STRONG', 'B' or 'b' to match on the HTML markup for bold. The template then replaces the matched HTML string with its XSLFO equivalent. The posted sample has some more complex examples handling lists, bullets, etc. So thats the sub template, now we need to register and call in it in the main template.
In the  top of the main template we register our interest in the sub template thus:

<?import:file:///c:temphtmlmarkup.xsl?>
Im using a the file URI to be able to run it on my desktop for the sample but you can use a full URL if you are using the Enterprise release or the XMLP URI reference if you are using EBS, see the user guide on referencing sub templates.

Our main template is now aware of the sub template, we now need to call the functions therein to get our html converted. For each field in our RTF template that might have HTML markup we need to call for the markup functions to be applied this requires a simple call:

<xsl:apply-templates select="PROJECTSCOPE"/>


Sadly we have to resort to XSL as the XMLP aliases do not support calling a template on a data element yet. This command tells the processor to apply all templates to the value of the element PROJECTSCCOPE. It will then cycle through the sub template functions looking for a match. You need to do this for all the fields that may have HTML markup in the XML data.

Now when you run the template against the XML the HTML markup will be converted to XSLFO markup et voila you have correctly formatted text in your output. You can get the complete example here.

Happy Templating

Thursday Nov 09, 2006

How about another date?

[Read More]

Friday Nov 03, 2006

Let's Date ...

[Read More]
About

Follow bipublisher on Twitter Find Us on Facebook BI Publisher Youtube ChannelDiscussion Forum

Join our BI Publisher community to get the most and keep updated with the latest news, How-to, Solutions! Share your feedback and let us hear your voice @bipublisher on Twitter, on our official Facebook page, and Youtube!

Search

Archives
« August 2015
SunMonTueWedThuFriSat
      
1
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
28
29
30
31
     
Today