HTML Rewriter : Document HTML « Development Class « Java

Home
Java
1.2D Graphics GUI
2.3D
3.Advanced Graphics
4.Ant
5.Apache Common
6.Chart
7.Class
8.Collections Data Structure
9.Data Type
10.Database SQL JDBC
11.Design Pattern
12.Development Class
13.EJB3
14.Email
15.Event
16.File Input Output
17.Game
18.Generics
19.GWT
20.Hibernate
21.I18N
22.J2EE
23.J2ME
24.JavaFX
25.JDK 6
26.JDK 7
27.JNDI LDAP
28.JPA
29.JSP
30.JSTL
31.Language Basics
32.Network Protocol
33.PDF RTF
34.Reflection
35.Regular Expressions
36.Scripting
37.Security
38.Servlets
39.Spring
40.Swing Components
41.Swing JFC
42.SWT JFace Eclipse
43.Threads
44.Tiny Application
45.Velocity
46.Web Services SOA
47.XML
Java » Development Class » Document HTML 




HTML Rewriter
   
/*
 * Copyright 2000-2004 The Apache Software Foundation.
 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 
 *      http://www.apache.org/licenses/LICENSE-2.0
 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 *
 *
 *  COMPATIBILITY
 *  
 *      [28.01.2001, RammerI] Tested on W2K, with J2SE, JDK 1.3
 *      [29.01.2001, RammerI] Tested on W2K, with JDK 1.2.2
 *
 *
 *
 *  FEATURES
 *      = Rewriting of <A HREFs, <IMG SRCes, <FORM ACTIONs, <TD BACKGROUNDs,
 *          <INPUT SRCs, <APPLET CODEBASEs
 *      = Removal of <SCRIPT>, <STYLE>, <HEAD>, <EMBED>, <OBJECT>, <APPLET>,
 *          <NOSCRIPT>
 
 ****
 * Please include the following section in the WebPagePortlet documentation     
 ****
 * <CODE>
 *
 * The following describes how HTML tags are rewritten
 *
 * <!-- --> (HTML Comments)
 *   o Unless otherwise mentioned, comments are striped.
 
 * <A>
 *   o HREF attribute   - URL merged with base URL (See Note 1)
 *   o TARGET attribute - Set to "_BLANK" if it does not exist 
 *                        and openInNewWindow = TRUE
 * <AREA>
 *   o HREF attribute   - URL merged with base URL (See Note 1)
 *   o TARGET attribute - Set to "_BLANK" if it does not exist 
 *                        and openInNewWindow = TRUE
 * <APPLET>
 *   o Optionally included
 *   o CODEBASE attribute - Set to the current path if it does
 *                          not exist.
 
 * <BASE>
 *   o <HEAD> does NOT have to be included.
 *   o HREF attribute  - Set the Base URL of the page, but the tag
 *                       not set in resulting HTML. URL merged with
 *                       base URL (See Note 1)
 
 * <BODY>
 *   o Background attribute - Always striped.
 
 * <EMBED>
 *   o May not work.  Not supported by JDK 1.3/
 
 * <FORM>
 *   o ACTION attribute - Set to the current URL if it does
 *                        not exist. URL merged with base
 *                        URL (See Note 1)
 
 * <IMG>
 *   o SRC attribute - URL merged with base URL (See Note 1)
 
 * <INPUT>
 *   o SRC attribute - URL merged with base URL (See Note 1)
 
 * <LINK>
 *   o HREF attribute - URL merged with base URL (See Note 1)
 *
 * <OBJECT>
 *   o Optionally included
 *   o CODEBASE attribute - Set to the current path if it does
 *                          not exist. URL merged with base
 *                          URL (See Note 1)
 
 * <SCRIPT>
 *   o Optionally included
 *   o Contents may be striped if this tag appears in the <HEAD>
 *     and the contents are NOT in a comment
 *   o SRC attribute - URL merged with base URL (See Note 1)
 *   o Script code that is NOT enclosed in a comment (<!-- -->)
 *     and in the <HEAD> may NOT be in the resulting HTML.  This
 *     is related to the HTML parser in included in the JDK 
 
 * <TD>
 *   o BACKGROUND attribute - URL merged with base URL (See Note 1)
 
 * Note 1: URL Merging.
 *   This is done because the source of the page sent to the
 *   user's browser is different then source the current page.
 *   Example:
 *     Base URL........ http://jakarta.apache.org/jetspeed
 *     URL............. logo.gif
 *     Resulting URL... http://jakarta.apache.org/jetspeed/logo.gif
 
 * </CODE>
 *  KNOWN PROBLEMS
 *
 *
 *  == Seems to have problems with international characters, when the web-pages
 *     are not downloaded from the original URL but taken from the cache.
 *     (To reproduce do the following
 *      1. create a new portlet from the url http://www.sycom.at/default.htm
 *      2. stop tomcat & restart tomcat
 *      3. login and customize your page to include this portlet
 *      4. everything should appear fine, the webpage will show some german 
 *         umlauts
 *      5. shutdown tomcat and restart it
 *      6. jetspeed is now taking the HTML not from www.sycom.at, but from the
 *         cache. Instead of the umlauts, you will see weird characters. 
 *
 *
 *  == Does not yet work with XHTML-Pages but only plain-old HTMLs. I.e. Closed
 *     single tags like <BR /> screw the output up.
 *      
 *
 *
 */
//package org.apache.jetspeed.util;

import java.io.Reader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.MutableAttributeSet;


/**
 *
 @author  Ingo Rammer ([email protected])
 @author <a href="mailto:[email protected]">Santiago Gala</a>
 @author <a href="mailto:[email protected]">Paul Spencer</a>
 @version 0.2
 */

public class HTMLRewriter 
{
    /**
     * Static initialization of the logger for this class
     */    
    
    private HTMLRewriter.Callback cb = new HTMLRewriter.Callback();
    
/** Sets the parameters for the HTMLRewriter
 @param removeScript Shall SCRIPT-Tags and their content be removed
 @param removeStyle Shall STYLE-Tags and their content be removed
 @param removeNoScript Shall NOSCRIPT-Tags and their content be removed
 @param removeMeta Shall META-Tags be removed
 @param removeApplet Shall APPLET-Tags and their content be removed
 @param removeObject Shall OBJECT-Tags and their content be removed
 @param removeHead Shall HEAD-Tags and their content be removed
 @param removeOnSomething Shall onClick, onBlur, etc. -Attributes be removed
 */    
    public HTMLRewriter(boolean removeScript,
                        boolean removeStyle,
                        boolean removeNoScript,
                        boolean removeMeta,
                        boolean removeApplet,
                        boolean removeObject,
                        boolean removeHead,
                        boolean removeOnSomething) {
        init removeScript,
        removeStyle,
        removeNoScript,
        removeMeta,
        removeApplet,
        removeObject,
        removeHead,
        removeOnSomething,
        false);
    }
        
    /**
     * Sets the parameters for the HTMLRewriter
     @param removeScript Shall SCRIPT-Tags and their content be removed
     @param removeStyle Shall STYLE-Tags and their content be removed
     @param removeNoScript Shall NOSCRIPT-Tags and their content be removed
     @param removeMeta Shall META-Tags be removed
     @param removeApplet Shall APPLET-Tags and their content be removed
     @param removeObject Shall OBJECT-Tags and their content be removed
     @param removeHead Shall HEAD-Tags and their content be removed
     @param removeOnSomething Shall onClick, onBlur, etc. -Attributes be removed
     */
    public HTMLRewriter(boolean removeScript,
                        boolean removeStyle,
                        boolean removeNoScript,
                        boolean removeMeta,
                        boolean removeApplet,
                        boolean removeObject,
                        boolean removeHead,
                        boolean removeOnSomething,
                        boolean openInNewWindow ) {
        init removeScript,
        removeStyle,
        removeNoScript,
        removeMeta,
        removeApplet,
        removeObject,
        removeHead,
        removeOnSomething,
        openInNewWindow )
    }

    /**
     * Sets the parameters for the HTMLRewriter
     *
     @param removeScript Shall SCRIPT-Tags and their content be removed
     @param removeStyle Shall STYLE-Tags and their content be removed
     @param removeNoScript Shall NOSCRIPT-Tags and their content be removed
     @param removeMeta Shall META-Tags be removed
     @param removeApplet Shall APPLET-Tags and their content be removed
     @param removeObject Shall OBJECT-Tags and their content be removed
     @param removeHead Shall HEAD-Tags and their content be removed
     @param removeOnSomething Shall onClick, onBlur, etc. -Attributes be removed
     @param openInNewWindow Shall links set Target="_blank"
     */
    private void init (boolean removeScript,
                       boolean removeStyle,
                       boolean removeNoScript,
                       boolean removeMeta,
                       boolean removeApplet,
                       boolean removeObject,
                       boolean removeHead,
                       boolean removeOnSomething,
                       boolean openInNewWindow 
    {
        cb.removeScript = removeScript;
        cb.removeStyle = removeStyle; 
        cb.removeNoScript = removeNoScript;
        cb.removeMeta = removeMeta;
        cb.removeApplet = removeApplet;
        cb.removeObject = removeObject;
        cb.removeHead = removeHead;
        cb.removeOnSomething = removeOnSomething;    
        cb.openInNewWindow = openInNewWindow;    
    }
    
    /**
     * Does the conversion of the HTML
     @param HTMLrdr Reader for HTML to be converted
     @param BaseUrl URL from which this HTML was taken. We be the base-Url
     * for all URL-rewritings.
     @throws MalformedURLException If the BaseUrl is not a valid URL or if an URL inside
     * the document could not be converted. Should not happen
     * normally, even in badly formatted HTML.
     @return HTML-String with rewritten URLs and removed (according
     * to constructor-settings) tags
     */
    public synchronized String convertURLs(Reader HTMLrdr, String BaseUrlthrows MalformedURLException
    {
        HTMLEditorKit.Parser parse = new HTMLRewriter.ParserGetter().getParser();        
        String res ="";
        try {
            if (cb.result != null) {
              cb.result = null;
              cb.result = new StringWriter();
            }
            cb.baseUrl = new URL(BaseUrl);
            parse.parse(HTMLrdr,cb,true);
            res = cb.getResult()
        catch (Exception e)
        {
            //logger.error( "Unable to convertURLS", e );
            throw new MalformedURLException(e.toString());
        }
        return res;
    }

    
    /** That Class is needed, because getParser is protected and therefore 
     *  only accessibly by a subclass
     */
    class ParserGetter extends HTMLEditorKit {
    /** This is needed, because getParser is protected
     @return Html Parser
     */        
      public HTMLEditorKit.Parser getParser(){
        return super.getParser();
      }
    

    
    class Callback extends HTMLEditorKit.ParserCallback {

        // the base-url of which the given html comes from.
        private URL baseUrl;

        // either handling of <FORM> is buggy, or I made some weird mistake ... 
        // ... JDK 1.3 sends double "</form>"-tags on closing <form>
        private boolean inForm = false

        
        // when in multi-part ignored tags (like <script> foobar </script>, 
        // <style> foobar </style>, a counter for the nesting-level will be
        // kept here
        private int ignoreLevel = 0;
        
        private boolean removeScript = true;
        private boolean removeStyle = true
        private boolean removeNoScript = true;
        private boolean removeMeta = true;
        private boolean removeApplet = true;
        private boolean removeObject = true;
        private boolean removeHead = true;
        private boolean openInNewWindow = false;
        
        // remove the onClick=, onBlur=, etc. - Attributes
        private boolean removeOnSomething = true;
        
        private boolean inScript = false;
        private boolean inStyle = false;
        
        private StringWriter result = new StringWriter();
        
        private Callback () {
        }
        
        
        private Callback addToResult(Object txt)
        {
            // to allow for implementation using Stringbuffer or StringWriter
            // I don't know yet, which one is better in this case
            if (ignoreLevel > 0return this;

            try {
                result.write(txt.toString());
            catch (Exception e) { /* ignore */ }
            return this;
        }

        private Callback addToResult(char[] txt)
        {
            if (ignoreLevel > 0return this;

            try {
                result.write(txt);
            catch (Exception e) { /* ignore */ }
            return this;
        }
        
        /** Accessor to the Callback's content-String
         @return Cleaned and rewritten HTML-Content
         */        
        public String getResult() {
            try {
                result.flush();
            catch (Exception e) { /* ignore */ }
            
            // WARNING: doesn't work, if you remove " " + ... but don't know why
            String res = " " + result.toString()

            return res;
        }
        
       
        public void flush() throws javax.swing.text.BadLocationException {
            // nothing to do here ...
        }

        /** 
         * Because Scripts and Stlyle sometimes are defined in comments, thoese
         * will be written. Otherwise comments are removed
         */
        public void handleComment(char[] values,int param) {
            if !inStyle || inScript))
                return;

            try {
                result.write("<!--");
                result.write(values);
                result.write("-->");
            catch (Exception e) { /* ignore */ }
          // we ignore them 
        }

        public void handleEndOfLineString(java.lang.String str) {
            addToResult("\n");
        }

        public void handleError(java.lang.String str,int param) {
            // ignored
        }

        public void handleSimpleTag(HTML.Tag tag,MutableAttributeSet attrs,int param) {
            if (removeMeta && (tag == HTML.Tag.META)) {
                return;
            }            
            appendTagToResult(tag,attrs);        
        }

        public void handleStartTag(HTML.Tag tag,  MutableAttributeSet attrs, int position) {
            appendTagToResult(tag,attrs);
        }

        public void handleEndTag(HTML.Tag tag, int position) {
            if ((tag ==HTML.Tag.FORM&& (inForm)) { 
                // form handling seems to be buggy
                addToResult("</").addToResult(tag).addToResult(">");
                inForm = false;
            else if (tag == HTML.Tag.FORM) {
                // do nothing! ... i.e. we are now outside of any <FORM>, so a
                // closing </form> is not really needed ... 
            else {
                addToResult("</").addToResult(tag).addToResult(">");
            }
            
            
            if ( (removeScript == false&& (tag == HTML.Tag.SCRIPT)) {
                inScript = false;
            else if ( (removeStyle == false&& (tag == HTML.Tag.STYLE)) {
                inStyle = false;
            }

            if removeScript && (tag == HTML.Tag.SCRIPT)) {
                ignoreLevel --;
            else if removeStyle && (tag == HTML.Tag.STYLE)) {
                ignoreLevel --;
            else if removeHead && (tag == HTML.Tag.HEAD)) {
                ignoreLevel --;
            else if removeApplet && (tag == HTML.Tag.APPLET)) {
                ignoreLevel --;
            else if removeObject && (tag == HTML.Tag.OBJECT)) {
                ignoreLevel --;
            else if removeNoScript && (tag.toString().equalsIgnoreCase("NOSCRIPT"))) {
                ignoreLevel --;
            }
        }
  
        private void appendTagToResult(HTML.Tag tag, MutableAttributeSet attrs) {

            if (tag.toString().equalsIgnoreCase("__ENDOFLINETAG__")) {
                // jdk 1.2.2 places a tag <__ENDOFLINETAG__> in the result ...
                // we don't want this one
                return;
            }
            
            if (tag.toString().equalsIgnoreCase("__IMPLIED__")) {
                // jdk 1.3 places a tag <__IMPLIED__> in the result ...
                // we don't want this one
                return;
            }
            
            convertURLS(tag,attrs);
            Enumeration e = attrs.getAttributeNames();
            if (tag == HTML.Tag.BASE)
                return;
            
            addToResult("<").addToResult(tag);
            while (e.hasMoreElements()) {
                Object attr = e.nextElement();
                String attrName = attr.toString();
                String value = attrs.getAttribute(attr).toString();

                // include attribute only when Not(RemoveOnSomething = True and starts with "on")
                if (!(removeOnSomething
                && attrName.toLowerCase().startsWith("on")
                && (attrName.length() 2))) {
                    // Attribute included
                    addToResult(" ").addToResult(attr).addToResult("=\"")
                    .addToResult(value).addToResult("\"");
                }
            }
            addToResult(">");
        }
                   
        /** Here the magic happens.
         *
         * If someone wants new types of URLs to be rewritten, add them here
         @param tag TAG from the Callback-Interface
         @param attrs Attribute-Set from the Callback-Interface
         */
        
        private void convertURLSHTML.Tag tag, MutableAttributeSet attrs ) {

           // first we do an URL-rewrite on different tags
            
            if (tag == HTML.Tag.A) {
                if (attrs.getAttribute(HTML.Attribute.HREF!= null) {
                    // ---- CHECKING <A HREF
                    addConvertedAttributeHTML.Attribute.HREF,
                    attrs );
                }
                if ((attrs.getAttribute(HTML.Attribute.TARGET== null&& cb.openInNewWindow) {
                    attrs.addAttribute(HTML.Attribute.TARGET, "_BLANK");
                }
            else if (tag == HTML.Tag.AREA) {
                if (attrs.getAttribute(HTML.Attribute.HREF!= null) {
                    // ---- CHECKING <A HREF
                    addConvertedAttributeHTML.Attribute.HREF,
                    attrs );
                }
                if ((attrs.getAttribute(HTML.Attribute.TARGET== null&& cb.openInNewWindow) {
                    attrs.addAttribute(HTML.Attribute.TARGET, "_BLANK");
                }
            else if (((tag == HTML.Tag.IMG|| (tag == HTML.Tag.INPUT|| (tag == HTML.Tag.SCRIPT))
                         && (attrs.getAttribute(HTML.Attribute.SRC!= null)) {
                // ---- CHECKING <IMG SRC & <INPUT SRC
                addConvertedAttributeHTML.Attribute.SRC,
                                       attrs );
            else if (tag == HTML.Tag.LINK) {
                if (attrs.getAttribute(HTML.Attribute.HREF!= null) {
                    // ---- CHECKING <LINK HREF
                    addConvertedAttributeHTML.Attribute.HREF,
                    attrs );
                }
            else if tag == HTML.Tag.APPLET ) {
                // ---- CHECKING <APPLET CODEBASE=
                if (attrs.getAttribute(HTML.Attribute.CODEBASE== null) {
                    int endOfPath = baseUrl.toString().lastIndexOf("/");
                    attrs.addAttribute(HTML.Attribute.CODEBASE, 
                                       baseUrl.toString().substring(0,endOfPath +1));
                else {
                    addConvertedAttributeHTML.Attribute.CODEBASE, attrs );
                }
            else if (tag == HTML.Tag.OBJECT) {
                // ---- CHECKING <OBJECT CODEBASE=
                if (attrs.getAttribute(HTML.Attribute.CODEBASE== null) {
                    int endOfPath = baseUrl.toString().lastIndexOf("/");
                    attrs.addAttribute(HTML.Attribute.CODEBASE, 
                                       baseUrl.toString().substring(0,endOfPath +1));
                else {
                    addConvertedAttributeHTML.Attribute.CODEBASE, attrs );
                }
            else if (tag == HTML.Tag.BODY) {
                if (attrs.getAttribute(HTML.Attribute.BACKGROUND!= null) {
                    // background images are applied to the ENTIRE page, this remove them!
                    attrs.removeAttributeHTML.Attribute.BACKGROUND);
                }
            else if (tag == HTML.Tag.BASE) {
                if (attrs.getAttribute(HTML.Attribute.HREF!= null) {
                    try {
                        baseUrl = new URL(attrs.getAttribute(HTML.Attribute.HREF).toString());
                    catch (Throwable t) {
                       // logger.error( "HTMLRewriter: Setting BASE=" 
                       // + attrs.getAttribute(HTML.Attribute.HREF).toString()
                       // + t.getMessage());
                    }
                    attrs.removeAttribute(HTML.Attribute.HREF);
                }
            else if (tag == HTML.Tag.FORM) {
                // ---- CHECKING <FORM ACTION=
                  inForm = true// buggy <form> handling in jdk 1.3 
                  if (attrs.getAttribute(HTML.Attribute.ACTION== null) {
                      //self referencing <FORM>
                       attrs.addAttribute(HTML.Attribute.ACTION,
                                          baseUrl.toString());
                  else {
                        addConvertedAttributeHTML.Attribute.ACTION,
                                               attrs );
                  }
            else if (tag == HTML.Tag.TD) {
                // ---- CHECKING <TD BACKGROUND=
                  if ((attrs.getAttribute(HTML.Attribute.BACKGROUND== null)) {
                      addConvertedAttributeHTML.Attribute.BACKGROUND,
                                             attrs );
                  }
            }

            
            // then we check for ignored tags ...
            // btw. I know, that this code could be written in a shorter way, but
            // I think it's more readable like this ...

            // don't forget to add changes to  handleEndTag() as well, else 
            // things will get screwed up!
            
            if ( (removeScript == false&& (tag == HTML.Tag.SCRIPT)) {
                inScript = true;
            else if ( (removeStyle == false&& (tag == HTML.Tag.STYLE)) {
                inStyle = true;
            }

            if removeScript && (tag == HTML.Tag.SCRIPT)) {
                  ignoreLevel ++;
            else if removeStyle && (tag == HTML.Tag.STYLE)) {
                  ignoreLevel ++;
            else if removeHead && (tag == HTML.Tag.HEAD)) {
                  ignoreLevel ++;
            else if removeApplet && (tag == HTML.Tag.APPLET)) {
                  ignoreLevel ++;
            else if removeObject && (tag == HTML.Tag.OBJECT)) {
                  ignoreLevel ++;
            else if (removeNoScript && (tag.toString().equalsIgnoreCase("NOSCRIPT"))) {
                  ignoreLevel ++;
            }
        }

        /**
         *
         * Converts the given attribute to base URL, if not null
         *
         */
        private void addConvertedAttributeHTML.Attribute attr,
                                            MutableAttributeSet attrs ) {
            ifattrs.getAttributeattr != null ) {
                String attrSource =  attrs.getAttributeattr ).toString();
                attrs.addAttributeattr,
                                    generateNewUrlattrSource ) );
            }
        }
              
              
        private String generateNewUrl(String oldURL) {
            try {
                URL x = new URL(baseUrl,oldURL);
                return x.toString();
            catch (Throwable t) {
                if (oldURL.toLowerCase().startsWith("javascript:")) {
                    return oldURL;
                }
                //logger.error( "HTMLRewriter: Setting BASE="
                //+ baseUrl
                //+ " Old = "
                //+ oldURL
                //+ t.getMessage());
                return oldURL; // default behaviour ...
            }
        }

        public void handleText(char[] values,int param) {
            addToResult(values);
        }
    }
}

   
    
    
  














Related examples in the same category
1.HTMLDocument: Element Iterator Example
2.HTMLEditorKit DemoHTMLEditorKit Demo
3.SimpleAttributeSet ExampleSimpleAttributeSet Example
4.Text Tab SampleText Tab Sample
5.Styled DocumentStyled Document
6.Html utils for working with tag's names and attributes.
7.Escape HTML
8.Escape HTML
9.Encode HTML
10.Replace all the occurences of HTML escape strings with the respective characters.
11.HTML Encode
12.XMLWriter is a generic class that provides common behavior to writers of a tagged language such as XML, WordML and HTML.
13.Escape html entities.
14.Html Encoder
15.Remove Comment
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.