JEditorPane is removing CSS font styles
I am trying to get the JEditorPane to preserve any CSS font style. Unfortunately, it seems to be stripping it out altogether for paragraph tags (and other tags as well) and converting it to a font tag for the A tags.
Consider the following example:
import java.awt.BorderLayout;
import java.awt.Container;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;
public class EditorPaneTest
{
public static void main(String[] args)
{
String text = "<html><head></head><body><p style=\"padding-right: 10px; padding-left: 10px; font-size: 14px; line-height: 125%; font-family: Verdana;\">This is a test.</p>"
+ "<p><a href=\"http://www.google.com/\" style=\"font-size: 9px; margin-right: 10px; font-style: normal; font-family: Verdana;\">Google</a></p></body></html>";
JEditorPane editorPane = new JEditorPane("text/html", text);
开发者_JAVA百科 JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(new JScrollPane(editorPane), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
text = editorPane.getText();
System.out.println(text);
}
}
This produces the following output for the p and a tags:
<p style="padding-left: 10px; padding-right: 10px; line-height: 125%">
and
<a href="http://www.google.com/" style="margin-right: 10px"><font size="9px" face="Verdana">Google</font></a>
As you can see, it preserves the padding and margin styles but strips out the font style for the paragraph tag and converts it to a font tag for the A tag.
Before getText
is called, if you display it it will actually style the paragraph correctly.
How do I get it so that it will preserve the font attribute as is?
Ok,
Figured out the issue is definitely in the HTMLWriter
class. Unfortunately, they did not make it easy to override this class, but I beleive I have it.
import java.io.IOException;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.text.AttributeSet;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.CSS;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLWriter;
public class FixedHTMLWriter extends HTMLWriter
{
private Vector tags = new Vector(10);
private Vector tagValues = new Vector(10);
private Vector tagsToRemove = new Vector(10);
private MutableAttributeSet convAttr = new SimpleAttributeSet();
private MutableAttributeSet oConvAttr = new SimpleAttributeSet();
public FixedHTMLWriter(Writer w, HTMLDocument doc, int pos, int len)
{
super(w, doc, pos, len);
}
AttributeSet convertToHTML(AttributeSet from, MutableAttributeSet to)
{
if (to == null)
{
to = convAttr;
}
to.removeAttributes(to);
if (from != null)
{
Enumeration keys = from.getAttributeNames();
String value = "";
while (keys.hasMoreElements())
{
Object key = keys.nextElement();
if (key instanceof CSS.Attribute)
{
value += key + ": " + from.getAttribute(key) + ";";
if (keys.hasMoreElements())
value += " ";
}
else
{
to.addAttribute(key, from.getAttribute(key));
}
}
if (value.length() > 0)
{
to.addAttribute(HTML.Attribute.STYLE, value);
}
}
return to;
}
@Override
protected void closeOutUnwantedEmbeddedTags(AttributeSet attr) throws IOException
{
tagsToRemove.removeAllElements();
// translate css attributes to html
attr = convertToHTML(attr, null);
HTML.Tag t;
Object tValue;
int firstIndex = -1;
int size = tags.size();
// First, find all the tags that need to be removed.
for (int i = size - 1; i >= 0; i--)
{
t = (HTML.Tag) tags.elementAt(i);
tValue = tagValues.elementAt(i);
if ((attr == null) || noMatchForTagInAttributes(attr, t, tValue))
{
firstIndex = i;
tagsToRemove.addElement(t);
}
}
if (firstIndex != -1)
{
// Then close them out.
boolean removeAll = ((size - firstIndex) == tagsToRemove.size());
for (int i = size - 1; i >= firstIndex; i--)
{
t = (HTML.Tag) tags.elementAt(i);
if (removeAll || tagsToRemove.contains(t))
{
tags.removeElementAt(i);
tagValues.removeElementAt(i);
}
write('<');
write('/');
write(t.toString());
write('>');
}
// Have to output any tags after firstIndex that still remaing,
// as we closed them out, but they should remain open.
size = tags.size();
for (int i = firstIndex; i < size; i++)
{
t = (HTML.Tag) tags.elementAt(i);
write('<');
write(t.toString());
Object o = tagValues.elementAt(i);
if (o != null && o instanceof AttributeSet)
{
writeAttributes((AttributeSet) o);
}
write('>');
}
}
}
private boolean noMatchForTagInAttributes(AttributeSet attr, HTML.Tag t, Object tagValue)
{
if (attr != null && attr.isDefined(t))
{
Object newValue = attr.getAttribute(t);
if ((tagValue == null) ? (newValue == null) : (newValue != null && tagValue.equals(newValue)))
{
return false;
}
}
return true;
}
@Override
protected void writeEmbeddedTags(AttributeSet attr) throws IOException
{
// translate css attributes to html
attr = convertToHTML(attr, oConvAttr);
Enumeration names = attr.getAttributeNames();
while (names.hasMoreElements())
{
Object name = names.nextElement();
if (name instanceof HTML.Tag)
{
HTML.Tag tag = (HTML.Tag) name;
if (tag == HTML.Tag.FORM || tags.contains(tag))
{
continue;
}
write('<');
write(tag.toString());
Object o = attr.getAttribute(tag);
if (o != null && o instanceof AttributeSet)
{
writeAttributes((AttributeSet) o);
}
write('>');
tags.addElement(tag);
tagValues.addElement(o);
}
}
}
@Override
protected void writeAttributes(AttributeSet attr) throws IOException
{
convAttr.removeAttributes(convAttr);
convertToHTML(attr, convAttr);
Enumeration names = convAttr.getAttributeNames();
while (names.hasMoreElements())
{
Object name = names.nextElement();
if (name instanceof HTML.Tag || name instanceof StyleConstants || name == HTML.Attribute.ENDTAG)
{
continue;
}
write(" " + name + "=\"" + convAttr.getAttribute(name) + "\"");
}
}
}
And you need to override the HTMLEditorKit
class method write
as follows:
public void write(Writer out, Document doc, int pos, int len) throws IOException, BadLocationException
{
if (doc instanceof HTMLDocument)
{
FixedHTMLWriter w = new FixedHTMLWriter(out, (HTMLDocument) doc, pos, len);
w.write();
}
else if (doc instanceof StyledDocument)
{
MinimalHTMLWriter w = new MinimalHTMLWriter(out, (StyledDocument) doc, pos, len);
w.write();
}
else
{
super.write(out, doc, pos, len);
}
}
And set the overridden HTMLEditorKit
on the JEditorPane
using a call to setEditorKit
.
精彩评论