📄 htmlwriter.java
字号:
}
}
/**
* @see #setPreformattedTags(java.util.Set) setPreformattedTags
*/
public Set getPreformattedTags() {
return (Set) (preformattedTags.clone());
}
/**
* <p>
* Override the default set, which includes PRE, SCRIPT, STYLE, and
* TEXTAREA, case insensitively.
* </p>
*
* <p>
* <b>Setting Preformatted Tags </b>
* </p>
*
* <p>
* Pass in a Set of Strings, one for each tag name that should be treated
* like a PRE tag. You may pass in null or an empty Set to assign the empty
* set, in which case no tags will be treated as preformatted, except that
* HTML Comments will continue to be preformatted. If a tag is included in
* the set of preformatted tags, all whitespace within the tag will be
* preserved, including whitespace on the same line preceding the close tag.
* This will generally make the close tag not line up with the start tag,
* but it preserves the intention of the whitespace within the tag.
* </p>
*
* <p>
* The browser considers leading whitespace before the close tag to be
* significant, but leading whitespace before the open tag to be
* insignificant. For example, if the HTML author doesn't put the close
* TEXTAREA tag flush to the left margin, then the TEXTAREA control in the
* browser will have spaces on the last line inside the control. This may be
* the HTML author's intent. Similarly, in a PRE, the browser treats a
* flushed left close PRE tag as different from a close tag with leading
* whitespace. Again, this must be left up to the HTML author.
* </p>
*
* <p>
* <b>Examples </b>
* </p>
* <blockquote>
* <p>
* Here is an example of how you can set the PreformattedTags list using
* setPreformattedTags to include IFRAME, as well as the default set, if you
* have an instance of this class named myHTMLWriter:
*
* <pre>
* Set current = myHTMLWriter.getPreformattedTags();
* current.add("IFRAME");
* myHTMLWriter.setPreformattedTags(current);
*
* //The set is now <b>PRE, SCRIPT, STYLE, TEXTAREA, IFRAME</b>
*
*
* </pre>
*
* Similarly, you can simply replace it with your own:
*
* <pre>
*
*
* HashSet newset = new HashSet();
* newset.add("PRE");
* newset.add("TEXTAREA");
* myHTMLWriter.setPreformattedTags(newset);
*
* //The set is now <b>{PRE, TEXTAREA}</b>
*
*
* </pre>
*
* You can remove all tags from the preformatted tags list, with an empty
* set, like this:
*
* <pre>
*
*
* myHTMLWriter.setPreformattedTags(new HashSet());
*
* //The set is now <b>{}</b>
*
*
* </pre>
*
* or with null, like this:
*
* <pre>
*
*
* myHTMLWriter.setPreformattedTags(null);
*
* //The set is now <b>{}</b>
*
*
* </pre>
*
* </p>
* </blockquote>
*
* @param newSet
* DOCUMENT ME!
*/
public void setPreformattedTags(Set newSet) {
// no fancy merging, just set it, assuming they did a
// getExcludeTrimTags() first if they wanted to preserve the default
// set.
// resets, and safely empties it out if newSet is null.
preformattedTags = new HashSet();
if (newSet != null) {
Object aTag;
Iterator iter = newSet.iterator();
while (iter.hasNext()) {
aTag = iter.next();
if (aTag != null) {
preformattedTags.add(aTag.toString().toUpperCase());
}
}
}
}
/**
* DOCUMENT ME!
*
* @param qualifiedName
* DOCUMENT ME!
*
* @return true if the qualifiedName passed in matched (case-insensitively)
* a tag in the preformattedTags set, or false if not found or if
* the set is empty or null.
*
* @see #setPreformattedTags(java.util.Set) setPreformattedTags
*/
public boolean isPreformattedTag(String qualifiedName) {
// A null set implies that the user called setPreformattedTags(null),
// which means they want no tags to be preformatted.
return (preformattedTags != null)
&& (preformattedTags.contains(qualifiedName.toUpperCase()));
}
/**
* This override handles any elements that should not remove whitespace,
* such as <PRE>, <SCRIPT>, <STYLE>, and <TEXTAREA>.
* Note: the close tags won't line up with the open tag, but we can't alter
* that. See javadoc note at setPreformattedTags.
*
* @param element
* DOCUMENT ME!
*
* @throws IOException
* When the stream could not be written to.
*
* @see #setPreformattedTags(java.util.Set) setPreformattedTags
*/
protected void writeElement(Element element) throws IOException {
if (newLineAfterNTags == -1) { // lazy initialization check
lazyInitNewLinesAfterNTags();
}
if (newLineAfterNTags > 0) {
if ((tagsOuput > 0) && ((tagsOuput % newLineAfterNTags) == 0)) {
super.writer.write(lineSeparator);
}
}
tagsOuput++;
String qualifiedName = element.getQualifiedName();
String saveLastText = lastText;
int size = element.nodeCount();
if (isPreformattedTag(qualifiedName)) {
OutputFormat currentFormat = getOutputFormat();
boolean saveNewlines = currentFormat.isNewlines();
boolean saveTrimText = currentFormat.isTrimText();
String currentIndent = currentFormat.getIndent();
// You could have nested PREs, or SCRIPTS within PRE... etc.,
// therefore use push and pop.
formatStack.push(new FormatState(saveNewlines, saveTrimText,
currentIndent));
try {
// do this manually, since it won't be done while outputting
// the tag.
super.writePrintln();
if ((saveLastText.trim().length() == 0)
&& (currentIndent != null)
&& (currentIndent.length() > 0)) {
// We are indenting, but we want to line up with the close
// tag. lastText was the indent (whitespace, no \n) before
// the preformatted start tag. So write it out instead of
// the current indent level. This makes it line up with its
// close tag.
super.writer.write(justSpaces(saveLastText));
}
// actually, newlines are handled in this class by writeString,
// depending on if the stack is empty.
currentFormat.setNewlines(false);
currentFormat.setTrimText(false);
currentFormat.setIndent("");
// This line is the recursive one:
super.writeElement(element);
} finally {
FormatState state = (FormatState) formatStack.pop();
currentFormat.setNewlines(state.isNewlines());
currentFormat.setTrimText(state.isTrimText());
currentFormat.setIndent(state.getIndent());
}
} else {
super.writeElement(element);
}
}
private String justSpaces(String text) {
int size = text.length();
StringBuffer res = new StringBuffer(size);
char c;
for (int i = 0; i < size; i++) {
c = text.charAt(i);
switch (c) {
case '\r':
case '\n':
continue;
default:
res.append(c);
}
}
return res.toString();
}
private void lazyInitNewLinesAfterNTags() {
if (getOutputFormat().isNewlines()) {
// don't bother, newlines are going to happen anyway.
newLineAfterNTags = 0;
} else {
newLineAfterNTags = getOutputFormat().getNewLineAfterNTags();
}
}
// Convenience methods, static, with bunch-o-defaults
/**
* Convenience method to just get a String result.
*
* @param html
* DOCUMENT ME!
*
* @return a pretty printed String from the source string, preserving
* whitespace in the defaultPreformattedTags set, and leaving the
* close tags off of the default omitElementCloseSet set. Use one of
* the write methods if you want stream output.
*
* @throws java.io.IOException
* @throws java.io.UnsupportedEncodingException
* @throws org.dom4j.DocumentException
*/
public static String prettyPrintHTML(String html)
throws java.io.IOException, java.io.UnsupportedEncodingException,
org.dom4j.DocumentException {
return prettyPrintHTML(html, true, true, false, true);
}
/**
* Convenience method to just get a String result, but <b>As XHTML </b>.
*
* @param html
* DOCUMENT ME!
*
* @return a pretty printed String from the source string, preserving
* whitespace in the defaultPreformattedTags set, but conforming to
* XHTML: no close tags are omitted (though if empty, they will be
* converted to XHTML empty tags: <HR/> Use one of the write
* methods if you want stream output.
*
* @throws java.io.IOException
* @throws java.io.UnsupportedEncodingException
* @throws org.dom4j.DocumentException
*/
public static String prettyPrintXHTML(String html)
throws java.io.IOException, java.io.UnsupportedEncodingException,
org.dom4j.DocumentException {
return prettyPrintHTML(html, true, true, true, false);
}
/**
* DOCUMENT ME!
*
* @param html
* DOCUMENT ME!
* @param newlines
* DOCUMENT ME!
* @param trim
* DOCUMENT ME!
* @param isXHTML
* DOCUMENT ME!
* @param expandEmpty
* DOCUMENT ME!
*
* @return a pretty printed String from the source string, preserving
* whitespace in the defaultPreformattedTags set, and leaving the
* close tags off of the default omitElementCloseSet set. This
* override allows you to specify various formatter options. Use one
* of the write methods if you want stream output.
*
* @throws java.io.IOException
* @throws java.io.UnsupportedEncodingException
* @throws org.dom4j.DocumentException
*/
public static String prettyPrintHTML(String html, boolean newlines,
boolean trim, boolean isXHTML, boolean expandEmpty)
throws java.io.IOException, java.io.UnsupportedEncodingException,
org.dom4j.DocumentException {
StringWriter sw = new StringWriter();
OutputFormat format = OutputFormat.createPrettyPrint();
format.setNewlines(newlines);
format.setTrimText(trim);
format.setXHTML(isXHTML);
format.setExpandEmptyElements(expandEmpty);
HTMLWriter writer = new HTMLWriter(sw, format);
Document document = DocumentHelper.parseText(html);
writer.write(document);
writer.flush();
return sw.toString();
}
// Allows us to the current state of the format in this struct on the
// formatStack.
private class FormatState {
private boolean newlines = false;
private boolean trimText = false;
private String indent = "";
public FormatState(boolean newLines, boolean trimText, String indent) {
this.newlines = newLines;
this.trimText = trimText;
this.indent = indent;
}
public boolean isNewlines() {
return newlines;
}
public boolean isTrimText() {
return trimText;
}
public String getIndent() {
return indent;
}
}
}
/*
* <html> <head> <title>My Title </title> <style> .foo { text-align: Right; }
* </style> <script> function mojo(){ return "bar"; } </script> <script
* language="JavaScript"> <!-- //this is the canonical javascript hiding.
* function foo(){ return "foo"; } //--> </script> </head> <!-- this is a
* comment --> <body bgcolor="#A4BFDD" mojo="&"> entities:   &
* " < > %23 <p></p> <mojo> </mojo> <foo /> <table border="1"> <tr>
* <td><pre> line0 <hr /> line1 <b>line2, should line up, indent-wise </b> line
* 3 line 4 </pre></td><td></td></tr> </table> <myCDATAElement> <![CDATA[My
* data]]> </myCDATAElement> </body> </html>
*/
/*
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain copyright statements and
* notices. Redistributions must also contain a copy of this document.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name "DOM4J" must not be used to endorse or promote products derived
* from this Software without prior written permission of MetaStuff, Ltd. For
* written permission, please contact dom4j-info@metastuff.com.
*
* 4. Products derived from this Software may not be called "DOM4J" nor may
* "DOM4J" appear in their names without prior written permission of MetaStuff,
* Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
*
* 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
*
* THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -