ReportParser(3)

NAME
Lire::ReportParser - Event-driven API to manipulate Lire XML Reports

SYNOPSIS
    package MyParser;
    use Lire::ReportParser;
    use vars qw/@ISA/;
    @ISA = qw/Lire::ReportParser/;
    sub parse_end {
        return "Finished";
    }
    package main::
    my $parser = new MyParser;
    my $result = eval { $parser->parsefile( "report.xml" ) };
    die "Error parsing report.xml: $@" if $@
    print $result, "\n";

DESCRIPTION
The Lire::ReportParser module offers an event-driven interface to Lire XML reports. It's primary purpose is to write custom handlers for the Lire XML Report format.

USING Lire::ReportParser
You create an instance of a subclass of Lire::ReportParser and uses either one of the parse() or parsefile() method to process the XML reports. You'll never probably use the Lire::ReportParser module directly but always one subclass which actually does something when processing the document.

  new( %args )
    my $parser = new Lire::ReportParser::ChartWriter( format => "png" );
The new method takes parameters in the form of key => value pairs. The available parameters is specific to each processor. There are no generic parameters.

  parse( $fh )
This method parse the Lire XML report and returns a processor-specific result. It will die() if an error is encountered. Error should be trapped using an eval() block. The parameter is an open file handle.

  parsefile( $filename )
This method parse the Lire XML report and returns a processor-specific result. It will die() if an error is encountered. Error should be trapped using an eval() block. The parameter is the name of a file which contains a Lire XML Report.

WRITING XML REPORT PROCESSOR USING Lire::ReportParser
The programming model is similar to the expat event-based interface or the well-known SAX model. The principal difference with those models is that this module offers hooks specifically tailored for Lire's XML reports. For example, instead of having one generic element-start event, you have methods for each specific type of elements making it easy to hook on only on the elements you're interested in. It also offers some functions that makes it easy to determine the context (always a difficulty in event-based programming).

If you are uncomfortable with that kind of programming, there is also an object-oriented API available to the XML reports. That API is more similar to DOM type of programming. Its principal drawback is that its less performant since it has to parse the whole XML document in memory to build an object representation. But if you need to "navigate" the document, it's a lot better than the event-based API.

The main way of using that API to write a custom XML report handler is by subclassing the Lire::ReportParser module and overriding the functions related to the element you are interested in.

There are 3 categories of methods you can override.

Customization Methods
    Those are methods that customize the way the Lire::ReportParser will operate. The most important one is the new() "constructor" and the one that determine which DocBook elements will trigger events.

Generic element methods
    Those are methods that are invoked on each elements before the more specific or higher one and can be used to hook before the other events are synthesized.

High-level methods
    Those are methods that are called on high-level report element and remove the processor from the burden of tracking the XML processing. For example, to process a value, you only have to override the handle_value() method instead of hooking on the value_start(), value_char() and value_end() method.

    There will be also method called element_name_start() and element_name_end() that will be invoked as each XML element is parsed. Element that contains character data (as opposed to containing only other XML elements) will trigger a element_name_char() method.

The module also provides some utility methods and context-determining methods that you'll probably want to use.

  NOTES ON NAMESPACE, ELEMENT NAME AND DOCBOOK
Elements in the Lire XML Report Markup Language are defined in the http://www.logreport.org/LRML/ namespace (which is usually mapped to the "lire" prefix). THE METHODS DO NOT CONTAINS THE PREFIX. You should override report_start() and not lire:report_start().

When an element name contains an hyphen "-", this is mapped to an underscore in the method's name. For example, the "missing-subreport" element will invoke the missing_subreport_start() and missing_subreport_end() methods.

The name of the methods used to process the DocBook elements starts by "dbk_": dbk_para_start(), dbk_para_end(), dbk_para_char(), etc.

Most Lire XML Reports contains some form of DocBook markup (in the description element), by default no specialize methods will be invoked for those elements (only the generic one). (There is a customization method that can be used to trigger specicialiez events).

For processors that are only interested in a plain text representation of the adequate description, there is a Lire::ReportParser::DocBookFormatter module from which they can inherit to receive the appropriate plain text descriptions in a handle_description() method without having to process DocBook themselves.

UTILITY METHODS
This section documents the utility methods offered by the Lire::ReportParser interface.

  original_string( )
This method returns the string that triggered the event. That's exactly the string as it appears in the source document.

  depth( )
Returns the number of opened and not yet closed elements. In element_name_start() and element_name_end() methods, the just-opened (or just to be closed element) isn't counted.

  in_element( $element_name )
This returns true if the innermost currently opened element has the same name as $element_name. $element_name is a string. If the element you are looking is a Lire XML Report Element, prefix it with "lire:".

Example:

    if ( $self->in_element( "lire:report") ) {
        # Parent element is a Lire report element.
    } elsif ( $self->in_element( "listitem" ) ) {
        # We are in a DocBook listitem element
    }

  within_element( $element_name )
This returns the number of times an element is opened in the current element ancestor. Like for the in_element(), the element's name should starts with "lire:" if it's a Lire XML Report element, otherwise it looks for DocBook elements. Also, when called from *_start() or *_end() methods, the "current" element isn't counted.

  is_lire_element( $name )
The element_start() and element_end() methods receive as parameter the name of the element currently being processed. The element name doesn't contains the namespace prefix, you should use this method to test wheter the name is a Lire XML Report element or a DocBook element. This method will return true if the element name was declared in the proper Lire namespace.

  skip( )
No element methods will be invoked until the current element is closed. This has the effect of restarting processing after the current element close.

  error( $msg )
Aborts the current parse with the $msg error message. Use this method instead of die()-ing.

  warning( $msg )
Prints the $msg message.

  expat( )
This method gives access to the underlying XML::Parser::Expat instance which used to do the actual XML processing. This can be used for more specialized processing.

CUSTOMIZATION METHODS
This section documents the methods that can be overriden to control some of the behavior the Lire::ReportParser instance.

  new( [%args] )
The subclass should call its parent new method. The only argument currently for the Lire::ReportParser is all_entries which should only be used by subclasses. Its purpose is to determine if all or only entries that should be displayed should trigger events. Default is to trigger events only for entries that should be displayed.

Of course, subclasses are free to define other arguments.

The object created is an hash reference. Subclasses are free to use the hash to store some of their state. All keys used by the Lire::ReportParser module are prefixed by "lrp_".

  known_dbk_elements( )
This method is called during initalization to let the subclass tell which DocBook elements it is interested to receive events for. If you don't override this, no specialized method will be called when encountering DocBook elements.

The object should returns a reference to an array containing the DocBook elements it wants a method to be invoked.

Example:

    sub known_dbk_elements {
        return [ qw/para listitem/ ];
    }

  known_dbk_pcdata_elements( )
This method is called during initalization to let the subclass tell it in which DocBook elements containing PCDATA (that is elements that can contains character data instead or in addition to other elements) the processor is interested to receive events for. If you don't override this, no specialized method will be called when encountering DocBook elements.

The object should returns a reference to an array containing the DocBook elements containing PCDATA it wants a method to be invoked. This should be a subset of the elements returned by known_dbk_elements() method.

Example:

    sub known_dbk_pcdata_elements {
        return [ "para" ];
    }

  parse_start( )
This methods is invoked once before the document is parsed. It can be used for any initialization the processor has to do.

  parse_end( )
This methods is invoked once after all the XML report was processed. The value that this method returns will be returned by the parse() or parsefile() method (whichever was used to start the parsing).

GENERIC METHODS
This section documents the method that are called before the specialized method or the high-level methods are called. In each of those mehods, you should return 0 if you want the normal processing to continue. Returning a true value means that the Lire::ReportParser instance shouldn't invoke the higher-level methods.

  element_start( $name, %attr )
This method is called each time an element start tag is encountered. The $name parameter contains the element name (use is_lire_element() to test for proper namespace). The remaining parameters are the attribute names and their values that are set in the element.

If this method returns true, higher-level methods won't be invoked.

  element_end( $name )
This method is called each time an element end tag is encountered. (For empty elements, this method is called just after the element_start() method.) The $name parameter contains the element name (use is_lire_element() to test for proper namespace).

If this method returns true, higher-level methods won't be invoked.

  pcdata( $text )
This method is called each time character data is encountered in elements that are declared to contain parsed character data. The $text parameter contains the character data.

When no DocBook elements were declared known, all DocBook elements will be considered to conains character data.

If this method returns true, higher-level methods won't be invoked.

  ignorable_ws( $text )
This method is called each time character data is encountered in elements that are not declared to contain parsed character data. The $text parameter contains the white space data that should be ignored.

The whitespace is reported so that formatting information can be preserved by the processor.

Since no higher-level methods are invoked on ignorable white space, the return value of this method is ignored.

HIGH-LEVEL EVENT METHODS
For each element defined, an element_name_start() and an element_name_end() method are invoked. For elements that contains character data, an element_name_char() method will also be invoked altough, you probably want to hook onto the easier handle_element_name() methods in these cases.

When you override any of those mehod (except the handle_element_name() one), you must invoke the parent method also:

    sub subreport_start {
        my $self = shift;
        my ( $name, %attr ) = @_;
        $self->SUPER::subreport_start( @_ );
        # Processor specific handling.
    }

  report_start( %attr )
Called when the report element start tag is encountered.

The only defined attribute is "version" and it should be equal to "1.0".

  report_end( )
Called when the report element end tag is encountered.

  handle_title( $title )
Method invoked after the "title" element was processed. The $title parameter contains the content of the element. This can be a report's, subreport's, section's or image's title. You'll need to use the in_element() method to determine the context.

  description_start( %attr )
Called when the start tag of the "description" element is encountered. A "target-user" attribute may be available and will contains a code identifying the audience to which the description's content is tailored.

The description can be related to a section, the report or a subreport. You'll probably need to use the in_element() method to determine the context.

Remember that if you want to process the content of the description element, you'll probably want to enable some DocBook elements.

  description_end( )
Called when the "description" closing tag is encoutered.

  handle_hostname( $hostname )
Called after the "hostname" element was parsed. The $hostname parameter contains the content of the element. The hostname can be related to the overall report or only to a specific subreport. You'll want to use the in_element() method to determine the context.

  image_start( %attr )
Called when the "image"'s opening tag is encountered. The "format" attribute will contains the image's format.

  image_end( )
Called when the "image"'s closing tag is encountered.

  handle_file( $filename )
Called after the "filename" element was parsed. This element is present when a chart was generated for the current subreport. The $filename parameter contains the content of the element.

  handle_date( $date, $date_epoch )
Called after the "date" element was parsed. The formatted date is available in the $date parameter, the date in number of seconds since the epoch is available in the $date_epoch parameter.

This can be the report's or a subreport's date, you'll need to use the in_element() method to determine the appropriate context.

  handle_timespan( $timespan, $epoch_start, $epoch_end )
Called after the "timespan" element was parsed. The formatted timespan is available in the $timespan parameter, the starting and ending dates of the timespan are available as number of seconds since the epoch in the $epoch_start and $epoch_end parameters.

This can be the timespan of the report or the subreport, you'll need to use the in_element() method to determine the appropriate context.

  section_start( )
Called when the opening tag of a "section" element is encountered.

  section_end( )
Called when the closing tag of a "section" element is encountered.

  missing_subreport_start( %attr )
Called when the opening tag of a "missing-subreport" element is encountered. The "superservice" attribute contains the superservice's of the subreport, the "type" attribute contains the report specification ID and the "reason" attribute will contains the reason why the subreport is missing.

  missing_subreport_end( )
Called when the closing tag of a "missing-subreport" element is encountered.

  subreport_start( %attr )
Called when the opening tag of the "subreport" element is encountered. The "superservice" attribute contains the subreport's superservice and the "type" attribute contains the ID of the report specification that was used to generate that subreport.

  subreport_end( )
Called when the "subreport"'s closing tag is encountered.

  table_start( %attr )
Called when the opening tag of the "table" element is encountered. The "charttype" attribute contains the chart's type that should be created for that data. The "show" attribute contains the maximum number of entries that should be displayed (there may more entries than this number).

  table_end( )
Called when the "table"'s closing tag is encountered.

  group_start( %attr )
Called when the opening tag of the "group" element is encountered. "group" elements introduce a kind of nested table. The "show" attribute contains the maximum number of entries that should be displayed, altough more entries may be present in the report.

  group_end( )
Called when the "group"'s closing tag is encountered.

  entry_start( %attr )
Called when the opening tag of an "entry" element is encountered. Unless the processor was initialized with the all_entries parameter (see the new() method), this method will be invoked only if the current entry should be display. Extra entries won't trigger a method invocation.

  entry_end( )
Called when the "entry"'s closing tag is encountered.

  handle_name( $name_rec )
Called after a "name" element was parsed. The $name_rec parameter is an hash reference which contains the different values of the name datum. Keys that are defined in this hash:

content
    That's the actual content of the name element. This contains the name in a format suitable for display.

value
    This contains the unformatted value of the name. For example, when the name is a time string, this attribute will contains the time in seconds since epoch.

range
    For some names, the actual content express a range (time, size, etc.). This attribute contains the length of the range.

  handle_value( $value_rec )
Called after a "value" element was parsed. The $value_rec parameter is an hash reference which contains the different values of the value datum. Keys that are defined in this hash:

content
    That's the actual content of the value element. This contains the value in a format suitable for display.

value
    This contains the unformatted value. For example, when bytes are displayed using "1M" or "1.1G", this will contains the value in bytes.

total
    This is used by values that represent an average. It contains the total which makes up the average.

n   This is used by values that represent an average. It contains the total which was used in the division to compute the average.

CONTEXT METHODS
Finally, here a bunch of additional methods that can be used to query some context information when processing elements.

  current_subreport_count( )
Returns the number of subreport that are present to date in the report. That number is equals to the number of processed "subreport" elements, i.e. the current subreport isn't counted untill the closing tag was processed.

  current_section_subreport_count( )
Returns the number of subreport that are present to date in the section. That number is equals to the number of processed "subreport" elements, i.e. the current subreport isn't counted untill the closing tag was processed.

  current_date( )
Returns the content of the "date" element that applies to the current element. This will either be the current subreport's date or the default one taken from the "report" element.

The date is returned as an hash reference which will contain the formatted date in the "date" key and the date in seconds since epoch in the "time" key.

  current_timespan( )
Returns the content of the "timespan" element that applies to the current element. This will either be the current subreport's date or the default one taken from the "report" element.

The timespan is returned as an hash reference which will contain the formatted timespan in the "timespan" key. The starting and ending date of the timespan are available as seconds since epoch in the "start" and "end" keys.

  current_superservice( )
Useful in "subreport" context, it returns the superservice's of the current subreport.

  current_type( )
Useful in "subreport" context, it returns the ID of the report specification that was used to generate the current subreport.

  current_charttype( )
Useful in "table" context, it returns the type of chart that should be generated for the current table.

  current_group_level( )
Useful in "table" context, it returns the number of nested group element. This will zero in the "table" element and incremented by one for every "group" element opened afterwards.

  current_group_entry_show( )
Useful in "table" and "group" context, it returns the maximum number of entries that should be displayed.

  show_current_entry( )
Useful in "entry" context when the "all_entries" option was set on the processor, this can be used to test whether or not the current "entry" should be displayed.

  current_table_entry_count( )
Useful in "table" context, it returns the number of entries that were processed so far. This only reports the entries in the "table" element, not counting the one in the nested "group".

  current_group_entry_index( )
Useful in "entry" context, it returns the index of the current entry in its parent. This will be zero for the first entry in the "table" element or for the first entry in each "group" element.

LIMITATIONS
WARNING: This module isn't multi-thread safe. You can't process more than one file concurrently.

SEE ALSO
Lire::Report(3pm) Lire::ReportParser::DocBookFormatter(3pm) Lire::ReportParser::ReportBuilder(3pm) Lire::ReportParser::AsciiWriter(3pm) Lire::ReportParser::ChartWriter(3pm) Lire::ReportParser::ExcelWriter(3pm)

VERSION
$Id: ReportParser.pm,v 1.18 2002/08/17 01:55:45 flacoste Exp $

COPYRIGHT
Copyright (C) 2001-2002 Stichting LogReport Foundation LogReport@LogReport.org

This file is part of Lire.

Lire is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program (see COPYING); if not, check with http://www.gnu.org/copyleft/gpl.html or write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.

AUTHOR
Francis J. Lacoste <flacoste@logreport.org>