vrijdag 24 augustus 2012

BiPublisher 10g: XSLT for HTML translations

Context


BiPublisher: 10.1.3.4.1

XSLT File

Here is a file you can use to transform HTML code into RTF code.
See this blog on how to use it.

<?xml version='1.0' encoding='utf-8'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
<xsl:output method="xml" encoding="UTF-8"/>
    <!-- CUSTOMIZE html->fo for Rich Text Editor-->
    <!-- elements -->
<xsl:template match="BLOCKQUOTE">
 <fo:block start-indent="0.25in">
 <xsl:apply-templates select="*|text()"/>
 </fo:block>
</xsl:template>
<xsl:template match="P|p">
 <fo:block white-space-collapse="false" padding-bottom="3pt" linefeed-treatment="preserve">
  <xsl:apply-templates select="text()|*|@*"/>
 </fo:block>
</xsl:template>
<xsl:template match="ol|OL">
  <fo:list-block provisional-distance-between-starts="1cm"
    provisional-label-separation="0.5cm">
    <xsl:attribute name="space-after">
      <xsl:choose>
        <xsl:when test="ancestor::ul or ancestor::ol">
          <xsl:text>0pt</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>12pt</xsl:text>
          </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
    <xsl:attribute name="start-indent">
      <xsl:variable name="ancestors">
        <xsl:choose>
          <xsl:when test="count(ancestor::ol) or count(ancestor::ul)">
            <xsl:value-of select="1 + 
                                  (count(ancestor::ol) + 
                                   count(ancestor::ul)) * 
                                  1.25"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:text>1</xsl:text>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:variable>
      <xsl:value-of select="concat($ancestors, 'cm')"/>
    </xsl:attribute>
    <xsl:apply-templates select="*"/>
  </fo:list-block>
</xsl:template>

<xsl:template match="ol/li|OL/LI">
  <fo:list-item>
    <fo:list-item-label end-indent="label-end()">
      <fo:block>
        <xsl:variable name="value-attr">
          <xsl:choose>
            <xsl:when test="../@start">
              <xsl:number value="position() + ../@start - 1"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:number value="position()"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="../@type='i'">
            <xsl:number value="$value-attr" format="i. "/>
          </xsl:when>
          <xsl:when test="../@type='I'">
            <xsl:number value="$value-attr" format="I. "/>
          </xsl:when>
          <xsl:when test="../@type='a'">
            <xsl:number value="$value-attr" format="a. "/>
          </xsl:when>
          <xsl:when test="../@type='A'">
            <xsl:number value="$value-attr" format="A. "/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:number value="$value-attr" format="1. "/>
          </xsl:otherwise>
        </xsl:choose>
      </fo:block>
    </fo:list-item-label>
    <fo:list-item-body start-indent="body-start()">
      <fo:block>
        <xsl:apply-templates select="*|text()"/>
      </fo:block>
    </fo:list-item-body>
  </fo:list-item>
</xsl:template>


<xsl:template match="ul|UL">
  <fo:list-block provisional-distance-between-starts="1cm"
    provisional-label-separation="0.5cm">
    <xsl:attribute name="space-after">
      <xsl:choose>
        <xsl:when test="ancestor::ul or ancestor::ol">
          <xsl:text>0pt</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>12pt</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
    <xsl:attribute name="start-indent">
      <xsl:variable name="ancestors">
        <xsl:choose>
          <xsl:when test="count(ancestor::ol) or count(ancestor::ul)">
            <xsl:value-of select="1 + 
                                  (count(ancestor::ol) + 
                                   count(ancestor::ul)) * 
                                  1.25"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:text>1</xsl:text>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:variable>
      <xsl:value-of select="concat($ancestors, 'cm')"/>
    </xsl:attribute>
    <xsl:apply-templates select="*"/>
  </fo:list-block>
</xsl:template>

<xsl:template match="ul/li|UL/LI">
  <fo:list-item>
    <fo:list-item-label end-indent="label-end()">
      <fo:block>&#x2022;</fo:block>
    </fo:list-item-label>
    <fo:list-item-body start-indent="body-start()">
      <fo:block>
        <xsl:apply-templates select="*|text()"/>
      </fo:block>
    </fo:list-item-body>
  </fo:list-item>
</xsl:template>
    
    <!--xsl:template match="OL|UL">
        <fo:list-block>
            <xsl:apply-templates/>
        </fo:list-block>
    </xsl:template>
    <xsl:template match="OL/OL|UL/UL">
        <fo:list-item>
            <fo:list-item-label>
                <fo:block/>
            </fo:list-item-label>
            <fo:list-item-body start-indent="body-start()">
                <xsl:apply-templates/>
            </fo:list-item-body>
        </fo:list-item>
    </xsl:template>
    <xsl:template match="LI">
        <fo:list-item>
            <fo:list-item-label end-indent="label-end()">
                <fo:block>
                    <xsl:choose>
                        <xsl:when test='name(..)!="OL"'>
                            <xsl:text>&#xb7;</xsl:text>
                        </xsl:when>
                        <xsl:when test='name(../..)!="OL"'>
                            <xsl:number format="(a)"/>
                        </xsl:when>
                        <xsl:when test='name(../../..)!="OL"'>
                            <xsl:number format="(1)"/>
                        </xsl:when>
                        <xsl:when test='name(../../../..)!="OL"'>
                            <xsl:number format="(i)"/>
                        </xsl:when>
                        <xsl:when test='name(../../../../..)!="OL"'>
                            <xsl:number format="(A)"/>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:text>&#xb7;</xsl:text>
                        </xsl:otherwise>
                    </xsl:choose>
                </fo:block>
            </fo:list-item-label>
            <fo:list-item-body start-indent="body-start()">
                <fo:block>
                    <xsl:apply-templates/>
                </fo:block>
            </fo:list-item-body>
        </fo:list-item>
    </xsl:template-->
    
    <xsl:template match="HR|hr">
        <fo:block text-align="justify">
            <fo:leader leader-pattern="rule">
                <xsl:apply-templates select="@*"/>
            </fo:leader>
        </fo:block>
    </xsl:template>
    <xsl:template match="BR|br">
        <xsl:text>
</xsl:text>
    </xsl:template>
    <xsl:template match="STRONG|strong|B|b">
        <fo:inline font-weight="bold">
            <xsl:apply-templates/>
        </fo:inline>
    </xsl:template>
    <xsl:template match="EM|I|i">
        <fo:inline font-style="italic">
            <xsl:apply-templates/>
        </fo:inline>
    </xsl:template>
    <xsl:template match="U|u">
        <fo:inline text-decoration="underline">
            <xsl:apply-templates/>
        </fo:inline>
    </xsl:template>

    <!-- attributes -->
    <xsl:template match="@align">
        <xsl:attribute name="text-align"><xsl:value-of select="."/></xsl:attribute>
    </xsl:template>

    <xsl:template match="@*">
</xsl:template>
</xsl:stylesheet>

donderdag 23 augustus 2012

Bi Publisher: usefull commands

Context

BiPublisher: 10.1.3.4.1
MSOffice: 2010

Usefull Commands

  • How to check the number of rows of a group?
    You want to know the number of rows that a group returns, to determine whether or not you want to show the for-each-loop or show something else.
    <?if:count(XML_GROUP_NAME)=0?><?end if?>
  • How to show/hide an entire section depending on a value?
    You are using sub-templates in your report.  You would like to hide or show such a sub-template depending on a parameter or a value. 
    <?if:DETAILS_VISIBLE='true'?>
    <?import:file:///export/home/bipublisher/Reports/ReusableLayouts/Details.rtf?>
    <?call@inlines: details_common?><?end call?> 
    <?end if?> 
    
    Now you want to do the same thing, but your sub-template is using other section layouts, like page orientation (portrait, landscape).  So the result of the if statement should not only reflect the sub-templae, but also the section in which it resides.  Do the following:
    <section break (next page)>
    <?import:file:///export/home/bipublisher/Reports/ReusableLayouts/Composition.rtf?>
    <?if@section:COMPOSITION_VISIBLE='true'?>
    <?call@inlines: composition_common?><?end call?> 
    <?end if?>
    <section break (next page)>
    
  •  
  • How do I show a different template, depending on a parameter?
    We have imported an RTF containing different templates.  Depending on a parameter, we want to show one of the templates.  You can use the following construct:
    <?import:file:///export/home/bipublisher/Reports/ReusableLayouts/Product.rtf?> 
    <?choose:?>
    <?when: .// PRODUCT_VARIANT =’productTab’?> <?call: product_common?> <?end when?>
    <?when: .// PRODUCT_VARIANT =’variant_a’?> <?call: product_variant_a?> <?end when?>
    <?when: .// PRODUCT_VARIANT =’variant_b’?> <?call: product_variant_b?> <?end when?>
    <?when: .// PRODUCT_VARIANT =’variant_c’?> <?call: product_variant_c?> <?end when?>
    <?end choose?>
    
  • How do I publish HTML-enabled content in my report ?
    We have a column containing in the database containing text with HTML-tags in.  We want to interprete these HTML-tags in our template.  For example: This is <b>bold</b>.
    • Make the column NCLOB capable.  You can perform this with a varchar2 or a clob column.

      select to_nclob(t.html_column) as "my_html"
      from my_table t;
    • Set the dataType in the datamodel

      <element name="my_html" dataType="xdo:xml"
      value="my_html"/>
    • Import the XSLT file to transform the HTML into RTF code.  You can do the import in the header of the page.  See this blog for an example of such a XSLT file.
    • In the template (RTF-layout), use the following field code
      <xsl:apply-templates select=".//MY_HTML"/>
      Attention: make sure you use the // or .// notitation.  Without it, it doesn't work.
  • How do I show an image in my report, that is comming from a blob column in the database?
    I want to show an image, that is stored as a blob-column in a database table.
    The following code, which you can use in your template assumes that the image is a jpeg.
    <fo:instream-foreign-object content-type="image/jpg"
    xdofo:alt="An Image">
    <xsl:value-of select=".//SIGNATUREIMG"/>
    </fo:instream-foreign-o>

maandag 6 augustus 2012

ADF: Programmatical views made simple

Challenge

How do I build a simple programmatical view object in ADF BC? I want to know what action to perform in which method and what the order of execution is of these different methods.

Context

JDeveloper version : 11.1.1.5.0 OS: Windows 7

Solution

We are going to build a programmatical view object based on static values. These are the different steps:

Create the Programmatical View

Launch the "New View Object" wizard
    Fill in the name of the view object and select the "Rows populated programmatically, not based on a query" data source type
    Create the attributes that you need.  Here we only created the primary key (Id) and the name (CountryName) attributes.
    Make sure that you always indicate at least one attribute as "Key Attribute" and also make sure that you put the "Updatable" property to "Always"
    Make sure you create the View Object Class, creating the View Row Class can be handy.  I'm using the View Row class in my example, so I need to generate this one also.

Create the necessary java code to override standard behavior

Here is the complete java code of the AllCountriesViewImpl class:
package model.hr.vo;

import java.sql.ResultSet;

import oracle.jbo.server.ViewObjectImpl;
import oracle.jbo.server.ViewRowImpl;
import oracle.jbo.server.ViewRowSetImpl;
// ---------------------------------------------------------------------
// ---    File generated by Oracle ADF Business Components Design Time.
// ---    Mon Aug 06 17:47:14 CEST 2012
// ---    Custom code may be added to this class.
// ---    Warning: Do not modify method signatures of generated methods.
// ---------------------------------------------------------------------
public class AllCountriesViewImpl extends ViewObjectImpl {
    /**
     * This is the default constructor (do not remove).
     */
    public AllCountriesViewImpl() {
    }
    
    // A simple structure to hold the different countries
    private String[] allCountries;
    

    /**
     * executeQueryForCollection - overridden for custom java data source support.
     */
    protected void executeQueryForCollection(Object qc, Object[] params, int noUserParams) {
        // Initialize the list of countries
        // This can be a call to anything returning your list of countries
        allCountries = new String[5];
        allCountries[0] = "Belgium";
        allCountries[1] = "The Netherlands";
        allCountries[2] = "Germany";
        allCountries[3] = "France";
        // Set the initial position
        setFetchPos(qc, 0);
        // Call the original method implementation
        super.executeQueryForCollection(qc, params, noUserParams);
    }

    /**
     * createRowFromResultSet - overridden for custom java data source support.
     */
    protected ViewRowImpl createRowFromResultSet(Object qc, ResultSet resultSet) {
        // Get the current fetch position
        int pos = getFetchPos(qc);
        // Create a new row
        AllCountriesViewRowImpl newRow = (AllCountriesViewRowImpl)createNewRowForCollection(qc);
        // Set the necessary fields 
        // This is why you need the RowImpl implementation
        newRow.setId(pos);
        newRow.setCountryName(allCountries[pos]);
        // Change the fetch position
        setFetchPos(qc, pos + 1);
        // Return the newly created row
        return newRow;
    }

    /**
     * hasNextForCollection - overridden for custom java data source support.
     */
    protected boolean hasNextForCollection(Object qc) {
        // Determine wether there are still countries to fetch from the array
        return getFetchPos(qc) < allCountries.length;
    }


    /**
     * getQueryHitCount - overridden for custom java data source support.
     */
    public long getQueryHitCount(ViewRowSetImpl viewRowSet) {
        long value = super.getQueryHitCount(viewRowSet);
        return value;
    }
    
    /**
     * Method to set the new fetch position
     * @param rowset
     * @param pos
     * @writer Filip Huysmans
     */
    private void setFetchPos(Object rowset, int pos) {
        if (pos == allCountries.length) {
            setFetchCompleteForCollection(rowset, true);
        }
        setUserDataForCollection(rowset, new Integer(pos));
    }

    /**
     * Method to get the current fetch position
     * @param rowset
     * @return
     * @writer Filip Huysmans
     */
    private int getFetchPos(Object rowset) {
        int value = ((Integer)getUserDataForCollection(rowset)).intValue();
        return value;
    }

}

The order in which these methods are executed, is:
  1. executeQueryForCollection: this is start of the query. Here you can do your initilizations and the fetching of the values that you need.
  2. createRowFromResultSet: this method will actually create a new row. This method is called for each iteration of the records you have.
  3. hasNextForCollection: this method determines whether there are still rows to be created. If it returns true, the createRowFromResultSet-method will be executed again. If it returns false, the creation of the records will end.
Now you can use this view object to create a table or use it as a LOV for an attribute.

Conclusion

With this simple example you should be able to start working with programmatical views.  This example only focusses on showing information.  There are circumstances where more complicated operations are needed.
I hope this was helpfull for you.

 

References