/* this belongs to the WebRaveler package */ package webraveler.html; import java.io.*; import au.id.jericho.lib.html.*; import java.util.*; import webraveler.http.HTTPRequest; import webraveler.http.HTTPResponse; /** * An HTMLPage2 is essentially just a String. The interesting * stuff all happens in the methods, but there's no extra * overhead of carrying around vectors or hashes or whatnot. * Just a String that we modify with the handy Jericho HTML * Parser. * * @author The Web Raveler Development Squad * @version 1.0 */ public class HTMLPage2 implements Serializable { private String html; /** * Make a new HTMLPage2 from the raw HTML string. * * @param html a String with html source to store */ public HTMLPage2(String html) { this.html = html; }//HTMLPage2(String) /** * Set the page's title to the given String. * * @param html */ public void setTitle(String title) { //make a new OutputDocument OutputDocument outputDocument=new OutputDocument(html); //make a Segment which spans the entire document Source source=new Source(html); //get a list of the BODY tags (though there should only be one) List linkStartTags=source.findAllStartTags(Tag.TITLE); //iterate over the TITLE tags for (Iterator i=linkStartTags.iterator(); i.hasNext();) { StartTag startTag=(StartTag)i.next(); //get the text following the TITLE tag Segment textSegment = startTag.getFollowingTextSegment(); //replace the above segment with the given String outputDocument.add(new StringOutputSegment(textSegment,title)); }//for //dump the resulting document to our html string html = outputDocument.toString(); }//void setTitle(String) /** * Set the page's HTML to the specified string. * * @param html a String containing the new HTML */ public void setText(String html) { this.html = html; }//void setText(String) /** * Replace text matching the given pattern (a regular expression) with * the replacement String. * * @param pattern a String regex whose matches we will replace * @param replacement the String containing the replacement text */ public void replaceText(String pattern, String replacement) { String oldText; //storage for original text String newText; //storage for replacement text //make a new OutputDocument OutputDocument outputDocument=new OutputDocument(html); //make a Segment which spans the entire document Source source=new Source(html); //get a list of the tags List startTags=source.findAllStartTags(); //iterate over the tags for (Iterator i=startTags.iterator(); i.hasNext();) { StartTag startTag=(StartTag)i.next(); //the next tag //check for an "alt" attribute, replacing text as necessary Attributes attribs = startTag.getAttributes(); if ( attribs != null ) { Attribute attr = attribs.get("alt"); if ( attr != null ) { Segment valueSegment = attr.getValueSegment(); oldText = valueSegment.getSourceText(); newText = oldText.replaceAll(pattern, replacement); outputDocument.add(new StringOutputSegment(valueSegment,newText)); }//if }//if //get the text following the tag Segment textSegment = startTag.getFollowingTextSegment(); //replace the pattern in the above segment oldText = textSegment.getSourceText(); newText = oldText.replaceAll(pattern,replacement); outputDocument.add(new StringOutputSegment(textSegment,newText)); }//for //dump the resulting document to our html string html = outputDocument.toString(); }//void replaceText(String,String) /** * Insert some text immediately after the HEAD tag (???). * * @param textToInsert */ public void insertAtTop(String textToInsert) { //make a new OutputDocument OutputDocument outputDocument=new OutputDocument(html); //make a Segment which spans the entire document Source source=new Source(html); //get a list of the BODY tags (though there should only be one) List linkStartTags=source.findAllStartTags(Tag.BODY); //iterate over the BODY tags for (Iterator i=linkStartTags.iterator(); i.hasNext();) { StartTag startTag=(StartTag)i.next(); //get the text following the BODY tag Segment textSegment = startTag.getFollowingTextSegment(); //add the new text to the start of the above text segment outputDocument.add(new StringOutputSegment(textSegment,textToInsert+textSegment.getSourceText())); }//for //dump the resulting document to our html string html = outputDocument.toString(); }//void insertAtTop(String) /** * Insert some text immediately before the end tag for the * BODY element. * * @param textToInsert */ public void insertAtBottom(String textToInsert) { //make a new OutputDocument OutputDocument outputDocument=new OutputDocument(html); //make a Segment which spans the entire document Source source=new Source(html); //get a list of the BODY tags (though there should only be one) List linkStartTags=source.findAllStartTags(Tag.BODY); //iterate over the BODY tags for (Iterator i=linkStartTags.iterator(); i.hasNext();) { StartTag startTag=(StartTag)i.next(); //get the matching end tag EndTag endTag = startTag.getElement().getEndTag(); if ( endTag == null ) return; //if there's no closing tag, quit //get the index in the source where the end tag starts int insertionPoint = endTag.getBegin(); //add the new text to the start of the above text segment outputDocument.add(new StringOutputSegment(insertionPoint,insertionPoint,textToInsert)); }//for //dump the resulting document to our html string html = outputDocument.toString(); }//void insertAtBottom(String) /** * Insert some text immediately after the HEAD tag. * * @param textToInsert */ public void insertInHead(String textToInsert) { //make a new OutputDocument OutputDocument outputDocument=new OutputDocument(html); //make a Segment which spans the entire document Source source=new Source(html); //get a list of the HEAD tags (though there should only be one) List linkStartTags=source.findAllStartTags(Tag.HEAD); //iterate over the HEAD tags for (Iterator i=linkStartTags.iterator(); i.hasNext();) { StartTag startTag=(StartTag)i.next(); //get the text following the HEAD tag Segment textSegment = startTag.getFollowingTextSegment(); //add the new text to the start of the above text segment outputDocument.add(new StringOutputSegment(textSegment,textToInsert+textSegment.getSourceText())); }//for //dump the resulting document to our html string html = outputDocument.toString(); }//void insertAtBottom(String) /** * Simply return the html source * * @return a String representation of this page */ public String toString() { return html; }//String toString() /** * Return an Enumeration of Strings containing all the * text between HTML tags or comments. * * @return an Enumeration of Strings of untagged text in the document */ public Enumeration getTextBlocks() { // we'll put the strings in a vector, then use Vector.elements() // to get the enumeration Vector vector = new Vector(); //make a new OutputDocument OutputDocument outputDocument=new OutputDocument(html); //make a Segment which spans the entire document Source source=new Source(html); //get a list of the tags List startTags=source.findAllStartTags(); //iterate over the tags for (Iterator i=startTags.iterator(); i.hasNext();) { StartTag startTag=(StartTag)i.next(); //the next tag //get the text following the tag, and put it in the vector Segment textSegment = startTag.getFollowingTextSegment(); String text = textSegment.getSourceText(); vector.add(text); }//for return vector.elements(); }// Enumeration getTextBlocks() public void makeURLsAbsolute(HTTPRequest request, HTTPResponse response) { //System.out.println("HTMLPage2: Making urls absolute"); String serverRoot; String uriString = request.uriString(); String docRoot; if (response.getHtmlPage() == null) return; if (uriString.equalsIgnoreCase("http://webraveler2.banner.bannerhtml")) return; /* figure out the document root and server root */ int thirdSlash = request.uriString().indexOf("/",7); if ( thirdSlash == -1 ) { uriString += "/"; thirdSlash = uriString.length()-1; }//if /* the prefix for URLs that start with "/" */ serverRoot = uriString.substring(0,thirdSlash); /* Fix for uris with /~name */ if (uriString.length() > thirdSlash+1 && uriString.charAt(thirdSlash+1) == '~') { int fourthSlash = uriString.indexOf('/',thirdSlash+1); if ( fourthSlash == -1 ) { uriString += "/"; fourthSlash = uriString.length()-1; } //if serverRoot = uriString.substring(0,fourthSlash); }//if /* it's nice to know where the last slash in the URL is, so that * we know the base for URLs that don't start with "/" */ int lastSlash = uriString.lastIndexOf("/"); if ( lastSlash == 6 ) { uriString += "/"; lastSlash = uriString.length()-1; }//if /* this string is the prefix for URLs that don't start with "/" or "http://" */ docRoot = uriString.substring(0,lastSlash+1); /* make URLs absolute for the following attribute names */ makeAttributeAbsolute(new String[]{"href","src","action"},docRoot,serverRoot); } private void makeAttributeAbsolute(String[] attributeNames,String docRoot,String serverRoot) { //Vector srcVector = (Vector) attributes.get(attributeName); //iterate over all StartTags in the document, //iterating over all matching Attribute elements. //make a new OutputDocument OutputDocument outputDocument=new OutputDocument(html); //make a Segment which spans the entire document Source source=new Source(html); //iterate over all tags in the document for ( Iterator i = source.getNextTagIterator(0) ; i.hasNext() ; ) { try { StartTag tag = (StartTag) i.next(); Attributes attribs = tag.getAttributes(); if ( attribs == null ) continue; for ( int k = 0 ; k < attributeNames.length ; k++ ) { Attribute attr = attribs.get(attributeNames[k]); if ( attr == null ) continue; Segment valueSegment = attr.getValueSegment(); StringBuffer sourceText = new StringBuffer(valueSegment.getSourceText()); //don't change urls that start with '#' if ( sourceText.charAt(0) == '#' ) continue; //a path from the server root if ( sourceText.charAt(0) == '/' ) { sourceText.insert(0, serverRoot); } else if (sourceText.toString().startsWith("http://") ) { // add trailing "/" to urls with no explicit paths from server root if ( sourceText.indexOf("/",7) == -1 ) { sourceText.insert(sourceText.length(),"/"); } } else { // get the document root, allowing for ".." in the path // ( e.g., "../../foo.html" ) String tempDocRoot = docRoot; while ( sourceText.toString().startsWith("../") ) { tempDocRoot = tempDocRoot.substring(0,1 + tempDocRoot.lastIndexOf('/',tempDocRoot.length()-2)); sourceText = sourceText.delete(0,3); }//while //for, e.g., "./foo.html" if ( sourceText.toString().startsWith("./") ) { sourceText = sourceText.delete(0,2); }//if sourceText.insert(0, tempDocRoot); //just add the docroot }//else // if it's an href, don't add the vurl if ( !attributeNames[k].equals("href") || !tag.getName().equalsIgnoreCase("a") ) { sourceText.insert(0,"http://temp.webraveler2.getunframeddocument/getunframeddocument!"); } else { //for hrefs in "a" tags, make the "target" attribute equal '_top' //in the enclosing tag Attribute targetAttr = attribs.get("target"); if ( targetAttr == null ) { //add a new "target" attribute to the tag outputDocument.add(new StringOutputSegment(tag.getEnd()-1,tag.getEnd()-1," target='_top'")); } else { //modify the existing "target" attribute Segment value = targetAttr.getValueSegment(); outputDocument.add(new StringOutputSegment(value,"_top")); }//else }//else //add the changes to our OutputDocument outputDocument.add(new StringOutputSegment(valueSegment,sourceText.toString())); }//for } catch( Exception e ) { } }//for html = outputDocument.toString(); }//makeAttributeAbsolute /** * Do a little self-testing... * * @param args */ public static void main( String[] args ) { String text = "\n\nFOO\n\n"; text += "\nHello, world!\n\"Google\"\n
\nGoogle was here!\n\"FOO\"\n\n"; System.out.println("text:======>\n"+text+"\n"); HTMLPage2 foo = new HTMLPage2(text); foo.insertAtTop("INSERTED_AT_THE_TOP"); System.out.println("HTMLPage2 output:======>\n"+foo); foo.insertAtBottom("INSERTED_AT_THE_BOTTOM"); System.out.println("HTMLPage2 output 2:======>\n"+foo); foo.setTitle("HAHAHAHAHA! I CHANGED THE TITLE!"); System.out.println("HTMLPage2 output 3:======>\n"+foo); foo.replaceText("[Gg]oogle","REPLACED SOME TEXT"); System.out.println("HTMLPage2 output 4:======>\n"+foo); foo.replaceText("LACE","----"); System.out.println("HTMLPage2 output 5:======>\n"+foo); System.out.println("\nGetting text blocks:"); //test the getTextBlocks() method int i=1; for ( Enumeration e = foo.getTextBlocks() ; e.hasMoreElements() ; i++ ) { String str = (String) e.nextElement(); System.out.println(i+" - '"+str+"'"); }//for }//main } // class HTMLPage