package freemind.main; /* * XHTMLWriter -- A simple XHTML document writer * * (C) 2004 Richard "Shred" Koerber * http://www.shredzone.net/ * * This is free software. You can modify and use it at will. */ import java.io.FileReader; import java.io.FileWriter; import java.io.FilterWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.html.HTMLDocument; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.Option; /** * Create a new XHTMLWriter which is able to save a HTMLDocument as XHTML. * <p> * The result will be a valid XML file, but it is not granted that the file will * really be XHTML 1.0 transitional conform. The basic purpose of this class * is to give an XSL processor access to plain HTML files. * * @author Richard "Shred" K�rber */ public class XHTMLWriter extends FixedHTMLWriter { private boolean writeLineSeparatorEnabled = true; /** * Create a new XHTMLWriter that will write the entire HTMLDocument. * * @param writer * Writer to write to * @param doc * Source document */ public XHTMLWriter(Writer writer, HTMLDocument doc) { this(writer, doc, 0, doc.getLength()); } /** * Create a new XHTMLWriter that will write a part of a HTMLDocument. * * @param writer * Writer to write to * @param doc * Source document * @param pos * Starting position * @param len * Length */ public XHTMLWriter(Writer writer, HTMLDocument doc, int pos, int len) { super(new XHTMLFilterWriter(writer), doc, pos, len); setLineLength(Integer.MAX_VALUE); } /** * Start the writing process. An XML and DOCTYPE header will be written * prior to the XHTML output. */ public void write() throws IOException, BadLocationException { // fc, 17.5.06: no special tags, as they are wrong inside XML tags like // <content>...<html>... // write( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ); // writeLineSeparator(); // write( "<!DOCTYPE html PUBLIC \"-//W3C//" // + "DTD XHTML 1.0 Transitional//EN\" " // + "\"DTD/xhtml1-transitional.dtd\">" ); // writeLineSeparator(); super.write(); } protected void writeOption(Option option) throws IOException { writeLineSeparatorEnabled = false; super.writeOption(option); writeLineSeparatorEnabled = true; write("</option>"); writeLineSeparator(); } protected void writeLineSeparator() throws IOException { if (writeLineSeparatorEnabled) super.writeLineSeparator(); } /** * Read HTML from the Reader, and send XHTML to the writer. Common mistakes * in the HTML code will also be corrected. The result is pretty-printed. * * @param reader * HTML source * @param writer * XHTML target */ public static void html2xhtml(Reader reader, Writer writer) throws IOException, BadLocationException { // --- Create a HTML document --- HTMLEditorKit kit = new HTMLEditorKit(); Document doc = kit.createDefaultDocument(); // --- Read the HTML source --- kit.read(reader, doc, doc.getLength()); // --- Write the content --- XHTMLWriter xhw = new XHTMLWriter(writer, (HTMLDocument) doc); xhw.write(); } /** * External call to convert a source HTML file to a target XHTML file. * <p> * Usage: <tt>java XHTMLWriter <source file> <target file></tt> * * @param args * Shell arguments */ public static void main(String[] args) { try { FileReader reader = new FileReader(args[0]); FileWriter writer = new FileWriter(args[1]); html2xhtml(reader, writer); writer.close(); reader.close(); } catch (Exception e) { freemind.main.Resources.getInstance().logException(e); } } /** * This FilterWriter will convert the output of Swing's HTMLWriter to XHTML * format. This is done by converting tags like <br> to * <br />. Also, special characters in tag attributes are * escaped. * <p> * This filter relies on known flaws of the HTMLWriter. It is known to work * with Java 1.4, but might not work with future Java releases. */ public static class XHTMLFilterWriter extends FilterWriter { private boolean insideTag = false; // We're inside a tag private boolean insideValue = false; // We're inside an attribute value private boolean readTag = false; // We're reading the tag name private String tag = ""; // Collector for the tag name /** * Create a new XHTMLFilterWriter. * * @param writer * Writer to write to */ public XHTMLFilterWriter(Writer writer) { super(writer); } /** * Write a single char to the Writer. * * @param c * Char to be written */ public void write(int c) throws IOException { if (insideValue) { // We're currently within a tag attribute's value. // Take care for proper HTML escaping. if (c == '&') { super.write("&", 0, 5); return; } else if (c == '<') { super.write("<", 0, 4); return; } else if (c == '>') { super.write(">", 0, 4); return; } else if (c == '"') { // leaving the value insideValue = false; } } else if (insideTag) { // We're inside a tag. Add a slash to the closing tag bracket // for // certain tags (like img, br, hr, input, ... ). if (readTag) { if (c == ' ' || c == '>') { // tag name ends readTag = false; } else { tag += (char) c; // collect tag name here } } if (c == '"') { // attribute value begins insideValue = true; } else if (c == '>') { // check if this is a "certain tag" if (tag.equals("img") || tag.equals("br") || tag.equals("hr") || tag.equals("input") || tag.equals("meta") || tag.equals("link") || tag.equals("area") || tag.equals("base") || tag.equals("basefont") || tag.equals("frame") || tag.equals("iframe") || tag.equals("col")) { super.write(" /"); // add slash to the closing bracket } insideTag = false; readTag = false; } } else if (c == '<') { // We're just at the very beginning of a tag. tag = ""; insideTag = true; readTag = true; } super.write(c); } /** * Write a char array to the Writer. * * @param cbuf * Char array to be written * @param off * Start offset within the array * @param len * Number of chars to be written */ public void write(char[] cbuf, int off, int len) throws IOException { while (len-- > 0) { write((int) cbuf[off++]); } } /** * Write a String to the Writer. * * @param str * String to be written * @param off * Start offset within the String * @param len * Number of chars to be written */ public void write(String str, int off, int len) throws IOException { write(str.toCharArray(), off, len); } } }