/*
* BioJava development code
*
* This code may be freely distributed and modified under the
* terms of the GNU Lesser General Public Licence. This should
* be distributed with the code. If you do not have a copy,
* see:
*
* http://www.gnu.org/copyleft/lesser.html
*
* Copyright for this code is held jointly by the individual
* authors. These should be listed in @author doc comments.
*
* For more information on the BioJava project and its aims,
* or to join the biojava-l mailing list, visit the home page
* at:
*
* http://www.biojava.org/
*
*/
package org.biojava.bio.program.blast2html;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* Takes a SAX event stream and a HTMLRenderer to produce
* a HTML Blast like program report.
*
*
* Primary author -
* Colin Hardman (CAT)
* Other authors -
* Tim Dilks (CAT)
* Simon Brocklehurst (CAT)
* Stuart Johnston (CAT)
* Lawerence Bower (CAT)
* Derek Crockford (CAT)
* Neil Benn (CAT)
*
* Copyright 2001 Cambridge Antibody Technology Group plc.
*
* This code released to the biojava project, May 2001
* under the LGPL license.
*
* @author Cambridge Antibody Technology Group plc
* @author Greg Cox
* @version 1.0
*/
public class Blast2HTMLHandler extends DefaultHandler {
/**
* Variables to hold data while parsing.
*
*/
private StringBuffer sb = new StringBuffer();
private String oProgram;
private String oVersion;
private String oQuery;
private String oDatabase;
private HitSummary oHitSummary = new HitSummary();
private HitId oHitId = new HitId();
private HitDescription oDesc = new HitDescription();
{
oHitSummary.oHitId = oHitId;
oHitSummary.oDesc = oDesc;
}
private DetailHit oDetailHit = new DetailHit();
private HSP oHSP = new HSP();
private HSPSummary oHSPSummary = new HSPSummary();
private BlastLikeAlignment oAlignment = new BlastLikeAlignment();
private Sequence oQuerySeq = new Sequence();
private Sequence oHitSeq = new Sequence();
{
oDetailHit.oHitId = oHitId;
oDetailHit.oDesc = oDesc;
oHSP.oHSPSummary = oHSPSummary;
oHSP.oAlignment = oAlignment;
oAlignment.oQuerySeq = oQuerySeq;
oAlignment.oHitSeq = oHitSeq;
}
private String oRawOutput = null;
// Flow control flags
private boolean inCollection = false;
private boolean firstSummary = true;
private boolean firstDetail = true;
/**
* The Class to render the HTML
*/
private HTMLRenderer oRenderer = null;
/**
* A content handler for rendering blast like outputs into
* HTML.
*
* @param poRenderer HTMLRenderer
- a configured
* HTMLRenderer.
*/
public Blast2HTMLHandler( HTMLRenderer poRenderer ) {
if ( poRenderer == null ) {
throw new IllegalArgumentException
( "HTMLRenderer cannot be null" );
}
oRenderer = poRenderer;
}
// ************************************************************ //
// **** ContentHandler overrides **** //
// ************************************************************ //
/**
* This is called when an element is entered. That is,
* the parser has met the first tag of the tag pair.
*
* @param poNameSpace String
- the name space.
* @param poElementName String
- the local name of the tag.
* @param poQName String
- the fully qualified name
* with prefix
* @param poAtts an Attributes
- the tag attributes.
* @exception SAXException if an error occurs
*/
public void startElement ( String poNameSpace, String poElementName,
String poQName, Attributes poAtts)
throws SAXException {
if ( poElementName.equals( "BlastLikeDataSetCollection" ) ) {
inCollection = true; // only checking to do - assume once
// inside collection it follows DTD
}
if ( inCollection ) {
if ( poElementName.equals( "BlastLikeDataSet" ) ) {
oProgram = poAtts.getValue( "program" );
oVersion = poAtts.getValue( "version" );
sb.setLength( 0 );
} else if ( poElementName.equals( "HitSummary" ) ) {
oHitSummary.score = poAtts.getValue( "score" );
oHitSummary.expectValue = poAtts.getValue( "expectValue" );
oHitSummary.numberOfHSPs = poAtts.getValue( "numberOfHSPs" );
oHitSummary.numberOfContributingHSPs = poAtts.getValue
( "numberOfContributingHSPs" );
oHitSummary.smallestSumProbability = poAtts.getValue
( "smallestSumProbability" );
oHitSummary.readingFrame = poAtts.getValue( "readingFrame" );
oHitSummary.numberOfDomains = poAtts.getValue
( "numberOfDomains" );
if ( firstSummary ) {
oRenderer.startSummaryTable( oHitSummary );
firstSummary = false;
}
//
// WHAT happens if there is more than one HSPCollection
// per hit - probably won't work.
//
//
} else if ( poElementName.equals( "HSPCollection" ) ) {
oRenderer.writeCurrentDetail( oDetailHit );
} else if ( poElementName.equals( "Hit" ) ) {
if ( firstDetail ) {
oRenderer.startDetailTable();
firstDetail = false;
}
oDetailHit.sequenceLength = poAtts.getValue
( "sequenceLength" );
} else if ( poElementName.equals( "HSPSummary" ) ) {
oHSPSummary.percentageIdentity = poAtts.getValue
( "percentageIdentity" );
oHSPSummary.score = poAtts.getValue( "score" );
oHSPSummary.expectValue = poAtts.getValue( "expectValue" );
oHSPSummary.alignmentSize = poAtts.getValue
( "alignmentSize" );
oHSPSummary.numberOfIdentities = poAtts.getValue
( "numberOfIdentities" );
oHSPSummary.hitStrand = poAtts.getValue( "hitStrand" );
oHSPSummary.queryStrand = poAtts.getValue( "queryStrand" );
oHSPSummary.queryFrame = poAtts.getValue( "queryFrame" );
oHSPSummary.hitFrame = poAtts.getValue( "hitFrame" );
oHSPSummary.numberOfPositives = poAtts.getValue
( "numberOfPositives" );
oHSPSummary.percentagePositives= poAtts.getValue
( "percentagePositives" );
oHSPSummary.pValue = poAtts.getValue( "pValue" );
oHSPSummary.sumPValues = poAtts.getValue( "sumPValues" );
oHSPSummary.numberOfGaps = poAtts.getValue( "numberOfGaps");
} else if ( poElementName.equals( "HitId" ) ) {
oHitId.id = poAtts.getValue( "id" );
oHitId.metaData = poAtts.getValue( "metaData" );
} else if ( poElementName.equals( "HitDescription" ) ) {
sb.setLength( 0 );
} else if ( poElementName.equals( "QuerySequence" ) ) {
oAlignment.oQuerySeq.startPosition =
poAtts.getValue( "startPosition" );
oAlignment.oQuerySeq.stopPosition =
poAtts.getValue( "stopPosition" );
sb.setLength( 0 );
} else if ( poElementName.equals( "MatchConsensus" ) ) {
sb.setLength( 0 );
} else if ( poElementName.equals( "HitSequence" ) ) {
oAlignment.oHitSeq.startPosition
= poAtts.getValue( "startPosition" );
oAlignment.oHitSeq.stopPosition
= poAtts.getValue( "stopPosition" );
sb.setLength( 0 );
} else if ( poElementName.equals( "RawOutput" ) ) {
sb.setLength( 0 );
}
} // end inCollection
}
/**
* Called when the end of an element is reached.
*
* @param poNameSpace a String
- the name space.
* @param poElementName a String
- the local element name.
* @param poQName a String
value - the qualified element name.
*/
public void endElement ( String poNameSpace,
String poElementName,
String poQName ) {
if ( poElementName.equals( "Header" ) ) {
this.getQueryIdAndDatabase();
oRenderer.writeTitleAndHeader( oProgram, oVersion,
oQuery, oDatabase );
} else if ( poElementName.equals( "HitDescription" ) ) {
oDesc.hitDescription = sb.substring(0);
} else if ( poElementName.equals( "Summary" ) ) {
oRenderer.endSummaryTable();
} else if ( poElementName.equals( "HitSummary" ) ) {
oRenderer.writeCurrentSummary( oHitSummary );
} else if ( poElementName.equals( "Detail" ) ) {
oRenderer.endDetailTable();
} else if ( poElementName.equals( "RawOutput" ) ) {
oRawOutput = sb.substring(0);
} else if ( poElementName.equals( "HSPSummary" ) ) {
oHSPSummary.rawOutput = oRawOutput;
} else if ( poElementName.equals( "QuerySequence" ) ) {
oAlignment.oQuerySeq.seq = sb.substring(0);
} else if ( poElementName.equals( "MatchConsensus" ) ) {
oAlignment.oConsensus = sb.substring(0);
} else if ( poElementName.equals( "HitSequence" ) ) {
oAlignment.oHitSeq.seq = sb.substring(0);
} else if ( poElementName.equals( "HSP" ) ) {
oRenderer.writeCurrentHSP( oHSPSummary, oAlignment );
} else if ( poElementName.equals( "BlastLikeDataSetCollection" ) ) {
this.reInit();
}
} // end
/**
* Describe characters
method here.
*
* @param charBuffer - character array containing data.
* @param start - the start position of relavent chars in passes array
* @param length - the stop position of relavent chars in passes array
*/
public void characters( char[] charBuffer, int start, int length) {
// note this may be called more than once for a particular tag
// ie loaded in chunks.
// So the correct way to handle this stuff is to buffer contents
// and deal with buffer when endElement is called.
sb.append( charBuffer, start, length );
}
// ************************************************************ //
// **** Utility functions **** //
// ************************************************************ //
/**
* Re-initializes state, called between parsings.
*/
void reInit() {
inCollection = false;
firstSummary = true;
firstDetail = true;
oRawOutput = null;
sb.setLength( 0 );
}
/**
* Parses out query and database id's from, the rawoutput.
*
* Changes in the Sax event generator may have made this redundant.
*
*/
void getQueryIdAndDatabase() {
BufferedReader reader = new BufferedReader
( new StringReader( sb.substring(0) ) );
String oLine;
try {
while (( oLine = reader.readLine() ) != null) {
if ( oLine.startsWith( "Query=" ) ) {
int index = oLine.indexOf( "=" );
oQuery = oLine.substring( index+1 ).trim();
continue;
}
if ( oLine.startsWith( "Database:" ) ) {
int index = oLine.indexOf( ":" );
oDatabase = oLine.substring( index+1 ).trim();
break;
}
}
}
catch ( IOException e ) {
printError( e );
}
}
/**
* Print an error to System.err
*
* @param e an Exception
*/
void printError( Exception e ) {
System.out.println( e.getMessage() );
e.printStackTrace();
}
} // end class
// ************************************************************ //
// **** Simple holder classes to hold temporary **** //
// **** values during parsing **** //
// ************************************************************ //
class DetailHit {
public String sequenceLength;
public HitDescription oDesc;
public HitId oHitId;
}
class HitDescription {
String hitDescription;
}
class HSP {
public HSPSummary oHSPSummary;
public BlastLikeAlignment oAlignment;
}
class HSPSummary {
public String score;
public String expectValue;
public String numberOfIdentities;
public String alignmentSize;
public String percentageIdentity;
public String hitStrand;
public String queryStrand;
public String queryFrame;
public String hitFrame;
public String numberOfPositives;
public String percentagePositives;
public String pValue;
public String sumPValues;
public String numberOfGaps;
public String rawOutput;
}
class BlastLikeAlignment {
public Sequence oQuerySeq;
public Sequence oHitSeq;
public String oConsensus;
}
class Sequence {
public String seq;
public String startPosition;
public String stopPosition;
}
class HitSummary {
public String score;
public String expectValue;
public HitId oHitId;
public HitDescription oDesc;
public String numberOfHSPs;
public String numberOfContributingHSPs;
public String smallestSumProbability;
public String readingFrame;
public String numberOfDomains;
}
class HitId {
public String id;
public String metaData;
}