Sunteți pe pagina 1din 8

Bordering Text

A tough little question appeared on one of our internal mailing lists today that piqued my interest. A customer
wanted to place a border around all data fields in their BIP output. Something like this:

Naturally you think of using a table, embedding the field inside a cell and turning the cell border on. That will
work but will need some finessing to get the cells to stretch or shrink depending on the width of the runtime
text. Then things might get a bit squirly (technical term) if the text is wide enough to force a new line at the
page edge. Anyway, it will get messy. So I took a look at the problem to see if the fields can be isolated in the
page as far as the XSLFO code is concerned. If the field can be siolated in its own XSL block then we can
change attribute values to get the borders to show just around the field. Sadly not.
This is an embedded field YEARPARAM in a sentence.
translates to
<fo:inline height="0.0pt" style-name="Normal" font-size="11.0pt" style-id="s0" whitespace-collapse="false" font-family-generic="swiss" font-family="Calibri"
xml:space="preserve">This is an embedded field <xsl:value-of select="(.//YEARPARAM)[1]"
xdofo:field-name="YEARPARAM"/> in a sentence.</fo:inline>

If we change the border on tis, it will apply to the complete sentence. not just the field.
So how could I isolate that field. Well we could actually do anything to the field. embolden, italicize, etc ... I
settled on changing the background color (its easy to change it back with a single attribute call.) Using the
highlighter tool on the Home tab in Word I change the field to have a yellow background. I now have:

This gives me the following code.


<fo:block linefeed-treatment="preserve" text-align="start" widows="2" end-indent="5.4pt"
orphans="2" start-indent="5.4pt" height="0.0pt" padding-top="0.0pt" paddingbottom="10.0pt" xdofo:xliff-note="YEARPARAM" xdofo:line-spacing="multiple:13.8pt">
<fo:inline height="0.0pt" style-name="Normal" font-size="11.0pt" style-id="s0" whitespace-collapse="false" font-family-generic="swiss" font-family="Calibri"
xml:space="preserve">This is an embedded field </fo:inline>
<fo:inline height="0.0pt" style-name="Normal" font-size="11.0pt" style-id="s0" whitespace-collapse="false"
font-family-generic="swiss" font-family="Calibri" background-color="#ffff00">
<xsl:attribute name="background-color">white</xsl:attribute> <xsl:value-of
select="(.//YEARPARAM)[1]" xdofo:field-name="YEARPARAM"/>
</fo:inline>
<fo:inline height="0.0pt" style-name="Normal" font-size="11.0pt" style-id="s0" whitespace-collapse="false" font-family-generic="swiss" font-family="Calibri"
xml:space="preserve"> in a sentence.</fo:inline>
</fo:block>

Now we have the field isolated we can easily set other attributes that will only be applied to the field and
nothing else. I added the following to my YEARPARAM field:
<?attribute@inline:background-color;'white'?> >>> turn the background back to white
<?attribute@inline:border-color;'black'?> >>> turn on all borders and make black
<?attribute@inline:border-width;'0.5pt'?> >>> make the border 0.5 point wide
<?YEARPARAM?> >>> my original field

The @inline tells the BIP XSL engine to only apply the attribute values to the immediate 'inline' code block i.e.
the field. Collapse all of this code into a single line in the field.
When I run the template now, I see the following:
Conditional Borders

How can you conditionally turn cells borders on and off in Publishers RTF/XSLFO templates? With a little
digging you'll find what appears to be the appropriate attributes to update in your template. You would logically
come up with using the various border styling options:
border-top|bottom|left|right-width
border-top|bottom|left|right-style
border-top|bottom|left|right-color

Buuuut, that doesnt work. Updating them individually does not make a difference to the output. Not sure why
and I will ask but for now here's the solution. Use the compound border formatter border-top|bottom|left|right.
This takes the form ' border-bottom="0.5pt solid #000000". You set all three options at once rather than
individually. In a BIP template you use:
<?if:DEPT='Accounting'?>
<?attribute@incontext:border-bottom;'3.0pt solid #000000'?>
<?attribute@incontext:border-top;'3.0pt solid #000000'?>
<?attribute@incontext:border-left;'3.0pt solid #000000'?>
<?attribute@incontext:border-right;'3.0pt solid #000000'?>
<?end if?>

3pt borders is a little excessive but you get the idea. This approach can be used with the if@row option too to
get the complete row borders to update. If your template will need to be run in left to right languages e.g. Arabic
or Hebrew, then you will need to use start and end in place of left and right.
For the inquisitive reader, you're maybe wondering how, did this guy know that? And why the heck is this not in
the user docs?
Other than my all knowing BIP guru status ;0) I hit the web for info on XSLFO cell border attributes and then
the Template Builder for Word. Particularly the export option; I generated the XSLFO output from a test RTF
template and took a look at the attributes. Then I started trying stuff out, Im a hacker and proud me! For the
users doc updates, I'll log a request for an update.
Desktop Testing XSL

Bit of a corner case this week but I wanted to park this as much for my reference as yours. Need to be able to
test a pure XSL template against some sample data? Thats an XSL template that is going to generate HTML,
Text or HTML. The Template Viewer app in the BI Publisher Desktop group does not offer that as an option. It
does offer XSL-FO proccesing thou.
A few minutes digging around in the java libraries and I came up with a command line solution that is easy to
set up and use.

1. Place your sample XML data and the XSL template in a directory
2. Open the lib directory where the TemplateViewer is installed. On my machine that is
d:\Oracle\BIPDesktop\TemplateViewer\lib
3. Copy the xmlparserv2.jar file into the directory created in step 1.
4. Use the following command in a DOS/Shell window to process the XSL template against the XML data.
java -cp ./xmlparserv2.jar oracle.xml.parser.v2.oraxsl fileX.xml fileY.xsl > fileX.xls

The file generated will depend on your XSL. For an Excel output, you would instruct the process to generate
fileX.xls in the same folder. You can then test the file with Excel, a browser or a text editor. Now you can test on
the desktop until you get it right without the overhead of having to load it to the server each time.
To be completely clear, this approach is for pure XSL templates that are designed to generate text, html or xml.
Its not for the XSLFO templates that might be used at runtime to generate PDF, PPT, etc. For those you should
use the Template Viewer application, it supports the XSLFO templates but not the pure XSL templates.
If your template still falls into the pure XSL template category. This will be down to you using some BIP
functionality in the templates. To get it to work you'll need to add in the Publisher libraries that contain the
function e.g. xdo-core.jar, i18nAPI_v3.jar, etc to the classpath argument (-cp.)
So a new command including the required libraries might look like:
java -cp ./xmlparserv2.jar;./xdo-core.jar;./i18nAPI_v3.jar oracle.xml.parser.v2.oraxsl
fileX.xml fileY.xsl > fileX.xls

You will need to either move the libraries to the local directory, my assumption above or include the full path to
them. More info here on setting the -cp attribute.
BIP 11g Dynamic SQL

Back in the 10g release, if you wanted something beyond the standard query for your report extract; you needed
to break out your favorite text editor. You gotta love 'vi' and hate emacs, am I right? And get to building a data
template, they were/are lovely to write, such fun ... not! Its not fun writing them by hand but, you do get to do
some cool stuff around the data extract including dynamic SQL. By that I mean the ability to add content
dynamically to your your query at runtime.
With 11g, we spoiled you with a visual builder, no more vi or notepad sessions, a friendly drag and drop
interface allowing you to build hierarchical data sets, calculated columns, summary columns, etc. You can still
create the dynamic SQL statements, its not so well documented right now, in lieu of doc updates here's the
skinny.
If you check out the 10g process to create dynamic sql in the docs. You need to create a data trigger function
where you assign the dynamic sql to a global variable that's matched in your report SQL. In 11g, the process is
really the same, BI Publisher just provides a bit more help to define what trigger code needs to be called. You
still need to create the function and place it inside a package in the db.
Here's a simple plsql package with the 'beforedata' function trigger.
Spec
create or replace PACKAGE BIREPORTS AS
whereCols varchar2(2000);
FUNCTION beforeReportTrig return boolean;

end BIREPORTS;

Body
create or replace PACKAGE BODY BIREPORTS AS
FUNCTION beforeReportTrig return boolean AS
BEGIN
whereCols := ' and d.department_id = 100';
RETURN true;
END beforeReportTrig;
END BIREPORTS;

you'll notice the additional where clause (whereCols - declared as a public variable) is hard coded. I'll cover
parameterizing that in my next post. If you can not wait, check the 10g docs for an example.
I have my package compiling successfully in the db. Now, onto the BIP data model definition.
1. Create a new data model and go ahead and create your query(s) as you would normally.
2. In the query dialog box, add in the variables you want replaced at runtime using an ampersand rather than a
colon e.g. &whereCols.
select
d.DEPARTMENT_NAME,
from
"OE"."EMPLOYEES" e, "OE"."DEPARTMENTS" d
where
d."DEPARTMENT_ID"= e."DEPARTMENT_ID"
&whereCols

Note that 'whereCols' matches the global variable name in our package. When you click OK to clear the dialog,
you'll be asked for a default value for the variable, just use ' and 1=1' That leading space is important to keep the
SQL valid ie required whitespace. This value will be used for the where clause if case its not set by the function
code.
3. Now click on the Event Triggers tree node and create a new trigger of the type Before Data. Type in the
default package name, in my example, 'BIREPORTS'. Then hit the update button to get BIP to fetch the valid
functions.

In my case I get to see the following:

Select the BEFOREREPORTTRIG function (or your name) and shuttle it across.
4. Save your data model and now test it. For now, you can update the where clause via the plsql package.
Next time ... parametrizing the dynamic clause.
Working the Chart Percentages

Charting in BIP is such fun, well sometimes it is. Not so much today, at least not for Ron in San Diego. He
needed a horizontal bar chart showing values plotted for various test areas with value labels at the end of the
bars. Simple enough right? The wrinkle, they were percentage values so he needed to see '56%' not '56'!
Still, it should be simple enough but the percentage formatting has a requirement for your values to be in a
decimal format i.e. 0.56 not 56.0. 56.0 gets formatted as 5600%. OK, so either pull the values out as decimals or
use the div function to divide the values in the chart by 100 e.g.
<xsl:value-of select="myval div 100)" />
Now I can use the following the chart XML to format the percentages as I need them:
<Graph ... >

<MarkerText visible="true">
<Y1ViewFormat>
<ViewFormat numberType="NUMTYPE_PERCENT" decimalDigit="0" numberTypeUsed="true"
leadingZeroUsed="true" decimalDigitUsed="true"/>
</Y1ViewFormat>
</MarkerText>
</Graph>

That gets me the values shown the way I want but the auto axis formatting gets me from 0 >> 1.

I now need to go in and add the formatting for the axis too.
<Graph ...>
<Y1Axis axisMinAutoScaled="false" axisMinValue="0.0" axisMaxAutoScaled="false"
axisMaxValue="1.0" majorTickStepAutomatic="true">
<ViewFormat numberType="NUMTYPE_PERCENT" decimalDigit="0" scaleFactor="SCALEFACTOR_NONE"
numberTypeUsed="true" leadingZeroUsed="true" decimalDigitUsed="true"
scaleFactorUsed="true"/>
</Y1Axis>

Now I have a chart that's showing the percentage values and formatting axis scale correctly for me too.

You can of course mess with the attributes above to get more decimal points on your labels, etc.
Happy Charting!
BI Publisher XDO_TOP - MSword Debugging
In several of my previous posts over the years, I've highlighted quite a few ways to turn on
debugging for the Oracle BI Publisher APIs. I really haven't gone to much into depth on how to
turn on debugging for the MSword template builder. I've outlined an approach below that I have
used with great success. In my opinion it's the easiest way to configure BI Publisher and debug
the BI Publisher APIs.
1. Create a directory on your C: drive called xdo_top
2. Create a sub-directory called temp: C:\xdo_top\temp
Create a sub-directory called resource: C:\xdo_top\resource
3. Create a xdodebug.cfg file in the resource directory with the following 2 lines:
LogLevel=STATEMENT
LogDir=C:\xdo_top\temp
4. Optionally copy an existing version xdo.cfg file if you need it for barcodes, micr fonts, etc.
Note: You can find this in one of the oracle bi publisher template builder directory's.
5. In MSWord goto the Add-ins menu for BIP, Click on -> tools->options->java options, Add the
following: -DXDO_TOP=C:\\xdo_top

Note: The screen shot also has a memory parameter, you do not need the memory option
-Xmx256M
6. Restart msword* Not really needed but a good idea
When you start bi publisher and preview a template from MSword the following should happen:

xdo.log should be created under c:\xdo_top\temp.

The log file should contain rich debugging information to help you with your
troubleshooting.

When would I need to use debugging?


As an example, let say you wanted to use the xdo.cfg file to configure a font, but that insolent
micr font isn't working in your template. You can review the log to see if it's indeed being pulled
in.

S-ar putea să vă placă și