|
|
|
@ -42,6 +42,9 @@ import org.xml.sax.XMLReader;
|
|
|
|
|
import org.xml.sax.ext.LexicalHandler; |
|
|
|
|
import org.xml.sax.helpers.XMLFilterImpl; |
|
|
|
|
|
|
|
|
|
import static org.dom4j.util.StringUtils.endsWithWhitespace; |
|
|
|
|
import static org.dom4j.util.StringUtils.startsWithWhitespace; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* <p> |
|
|
|
|
* <code>XMLWriter</code> takes a DOM4J tree and formats it to a stream as |
|
|
|
@ -54,7 +57,7 @@ import org.xml.sax.helpers.XMLFilterImpl;
|
|
|
|
|
* such as to allow suppression of the XML declaration, the encoding declaration |
|
|
|
|
* or whether empty documents are collapsed. |
|
|
|
|
* </p> |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* <p> |
|
|
|
|
* There are <code>write(...)</code> methods to print any of the standard |
|
|
|
|
* DOM4J classes, including <code>Document</code> and <code>Element</code>, |
|
|
|
@ -63,10 +66,10 @@ import org.xml.sax.helpers.XMLFilterImpl;
|
|
|
|
|
* preferred character encoding to be ignored. If you use encodings other than |
|
|
|
|
* UTF8, we recommend using the method that takes an OutputStream instead. |
|
|
|
|
* </p> |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @author <a href="mailto:jstrachan@apache.org">James Strachan </a> |
|
|
|
|
* @author Joseph Bowbeer |
|
|
|
|
* @version $Revision$ |
|
|
|
|
* @version $Revision: 1.83 $ |
|
|
|
|
*/ |
|
|
|
|
public class XMLWriter extends XMLFilterImpl implements LexicalHandler { |
|
|
|
|
private static final String PAD_TEXT = " "; |
|
|
|
@ -139,7 +142,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
private boolean inDTD; |
|
|
|
|
|
|
|
|
|
/** The namespaces used for the current element when consuming SAX events */ |
|
|
|
|
private Map namespacesMap; |
|
|
|
|
private Map<String, String> namespacesMap; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* what is the maximum allowed character code such as 127 in US-ASCII (7 |
|
|
|
@ -200,7 +203,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @return true if text thats output should be escaped. This is enabled by |
|
|
|
|
* default. It could be disabled if the output format is textual, |
|
|
|
|
* like in XSLT where we can have xml, html or text output. |
|
|
|
@ -213,7 +216,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* Sets whether text output should be escaped or not. This is enabled by |
|
|
|
|
* default. It could be disabled if the output format is textual, like in |
|
|
|
|
* XSLT where we can have xml, html or text output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param escapeText |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -225,7 +228,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* Set the initial indentation level. This can be used to output a document |
|
|
|
|
* (or, more likely, an element) starting at a given indent level, so it's |
|
|
|
|
* not always flush against the left margin. Default: 0 |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param indentLevel |
|
|
|
|
* the number of indents to start with |
|
|
|
|
*/ |
|
|
|
@ -237,7 +240,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* Returns the maximum allowed character code that should be allowed |
|
|
|
|
* unescaped which defaults to 127 in US-ASCII (7 bit) or 255 in ISO- (8 |
|
|
|
|
* bit). |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @return DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
|
public int getMaximumAllowedCharacter() { |
|
|
|
@ -254,7 +257,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* escape any characters (other than the special XML characters like < |
|
|
|
|
* > &) If this is not explicitly set then it is defaulted from the |
|
|
|
|
* encoding. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param maximumAllowedCharacter |
|
|
|
|
* The maximumAllowedCharacter to set |
|
|
|
|
*/ |
|
|
|
@ -264,7 +267,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Flushes the underlying Writer |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -274,7 +277,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Closes the underlying Writer |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -284,7 +287,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the new line text to the underlying Writer |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -294,10 +297,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the given {@link Attribute}. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param attribute |
|
|
|
|
* <code>Attribute</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -313,21 +316,21 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* <p> |
|
|
|
|
* This will print the <code>Document</code> to the current Writer. |
|
|
|
|
* </p> |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* <p> |
|
|
|
|
* Warning: using your own Writer may cause the writer's preferred character |
|
|
|
|
* encoding to be ignored. If you use encodings other than UTF8, we |
|
|
|
|
* recommend using the method that takes an OutputStream instead. |
|
|
|
|
* </p> |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* <p> |
|
|
|
|
* Note: as with all Writers, you may need to flush() yours after this |
|
|
|
|
* method returns. |
|
|
|
|
* </p> |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param doc |
|
|
|
|
* <code>Document</code> to format. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* if there's any problem writing. |
|
|
|
|
*/ |
|
|
|
@ -358,10 +361,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* s, and its value, and all its content (child nodes) to the current |
|
|
|
|
* Writer. |
|
|
|
|
* </p> |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param element |
|
|
|
|
* <code>Element</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -375,10 +378,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the given {@link CDATA}. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param cdata |
|
|
|
|
* <code>CDATA</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -392,10 +395,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the given {@link Comment}. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param comment |
|
|
|
|
* <code>Comment</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -409,10 +412,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the given {@link DocumentType}. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param docType |
|
|
|
|
* <code>DocumentType</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -426,10 +429,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the given {@link Entity}. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param entity |
|
|
|
|
* <code>Entity</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -443,10 +446,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the given {@link Namespace}. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param namespace |
|
|
|
|
* <code>Namespace</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -460,10 +463,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the given {@link ProcessingInstruction}. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param processingInstruction |
|
|
|
|
* <code>ProcessingInstruction</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -481,10 +484,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* Print out a {@link String}, Perfoms the necessary entity escaping and |
|
|
|
|
* whitespace stripping. |
|
|
|
|
* </p> |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param text |
|
|
|
|
* is the text to output |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -498,10 +501,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the given {@link Text}. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param text |
|
|
|
|
* <code>Text</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -515,10 +518,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the given {@link Node}. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param node |
|
|
|
|
* <code>Node</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -533,10 +536,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
/** |
|
|
|
|
* Writes the given object which should be a String, a Node or a List of |
|
|
|
|
* Nodes. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param object |
|
|
|
|
* is the object to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -546,10 +549,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
} else if (object instanceof String) { |
|
|
|
|
write((String) object); |
|
|
|
|
} else if (object instanceof List) { |
|
|
|
|
List list = (List) object; |
|
|
|
|
List<?> list = (List<?>) object; |
|
|
|
|
|
|
|
|
|
for (int i = 0, size = list.size(); i < size; i++) { |
|
|
|
|
write(list.get(i)); |
|
|
|
|
for (Object aList : list) { |
|
|
|
|
write(aList); |
|
|
|
|
} |
|
|
|
|
} else if (object != null) { |
|
|
|
|
throw new IOException("Invalid object: " + object); |
|
|
|
@ -561,16 +564,17 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* Writes the opening tag of an {@link Element}, including its {@link |
|
|
|
|
* Attribute}s but without its content. |
|
|
|
|
* </p> |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param element |
|
|
|
|
* <code>Element</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
|
public void writeOpen(Element element) throws IOException { |
|
|
|
|
writer.write("<"); |
|
|
|
|
writer.write(element.getQualifiedName()); |
|
|
|
|
writeNamespaces(element); |
|
|
|
|
writeAttributes(element); |
|
|
|
|
writer.write(">"); |
|
|
|
|
} |
|
|
|
@ -579,10 +583,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* <p> |
|
|
|
|
* Writes the closing tag of an {@link Element} |
|
|
|
|
* </p> |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param element |
|
|
|
|
* <code>Element</code> to output. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -599,8 +603,8 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
public void setProperty(String name, Object value) |
|
|
|
|
throws SAXNotRecognizedException, SAXNotSupportedException { |
|
|
|
|
for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) { |
|
|
|
|
if (LEXICAL_HANDLER_NAMES[i].equals(name)) { |
|
|
|
|
for (String lexicalHandlerName : LEXICAL_HANDLER_NAMES) { |
|
|
|
|
if (lexicalHandlerName.equals(name)) { |
|
|
|
|
setLexicalHandler((LexicalHandler) value); |
|
|
|
|
|
|
|
|
|
return; |
|
|
|
@ -612,8 +616,8 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
public Object getProperty(String name) throws SAXNotRecognizedException, |
|
|
|
|
SAXNotSupportedException { |
|
|
|
|
for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) { |
|
|
|
|
if (LEXICAL_HANDLER_NAMES[i].equals(name)) { |
|
|
|
|
for (String lexicalHandlerName : LEXICAL_HANDLER_NAMES) { |
|
|
|
|
if (lexicalHandlerName.equals(name)) { |
|
|
|
|
return getLexicalHandler(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -662,7 +666,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
public void startPrefixMapping(String prefix, String uri) |
|
|
|
|
throws SAXException { |
|
|
|
|
if (namespacesMap == null) { |
|
|
|
|
namespacesMap = new HashMap(); |
|
|
|
|
namespacesMap = new HashMap<String, String>(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
namespacesMap.put(prefix, uri); |
|
|
|
@ -975,10 +979,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
/** |
|
|
|
|
* Determines if element is a special case of XML elements where it contains |
|
|
|
|
* an xml:space attribute of "preserve". If it does, then retain whitespace. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param element |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @return DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
|
protected final boolean isElementSpacePreserved(Element element) { |
|
|
|
@ -986,12 +990,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
boolean preserveFound = preserve; // default to global state
|
|
|
|
|
|
|
|
|
|
if (attr != null) { |
|
|
|
|
if ("xml".equals(attr.getNamespacePrefix()) |
|
|
|
|
&& "preserve".equals(attr.getText())) { |
|
|
|
|
preserveFound = true; |
|
|
|
|
} else { |
|
|
|
|
preserveFound = false; |
|
|
|
|
} |
|
|
|
|
preserveFound = "xml".equals(attr.getNamespacePrefix()) && "preserve".equals(attr.getText()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return preserveFound; |
|
|
|
@ -1003,10 +1002,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* whitespace trimming occurs to avoid problems with multiple text nodes |
|
|
|
|
* being created due to text content that spans parser buffers in a SAX |
|
|
|
|
* parser. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param element |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -1023,34 +1022,34 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
// concatenate adjacent text nodes together
|
|
|
|
|
// so that whitespace trimming works properly
|
|
|
|
|
Text lastTextNode = null; |
|
|
|
|
StringBuffer buff = null; |
|
|
|
|
StringBuilder buff = null; |
|
|
|
|
boolean textOnly = true; |
|
|
|
|
|
|
|
|
|
for (int i = 0, size = element.nodeCount(); i < size; i++) { |
|
|
|
|
Node node = element.node(i); |
|
|
|
|
|
|
|
|
|
for (Node node : element.content()) { |
|
|
|
|
if (node instanceof Text) { |
|
|
|
|
if (lastTextNode == null) { |
|
|
|
|
lastTextNode = (Text) node; |
|
|
|
|
} else { |
|
|
|
|
if (buff == null) { |
|
|
|
|
buff = new StringBuffer(lastTextNode.getText()); |
|
|
|
|
buff = new StringBuilder(lastTextNode.getText()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
buff.append(((Text) node).getText()); |
|
|
|
|
buff.append((node).getText()); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (!textOnly && format.isPadText()) { |
|
|
|
|
// only add the PAD_TEXT if the text itself starts with
|
|
|
|
|
// whitespace
|
|
|
|
|
char firstChar = 'a'; |
|
|
|
|
final boolean startsWithWhitespace; |
|
|
|
|
if (buff != null) { |
|
|
|
|
firstChar = buff.charAt(0); |
|
|
|
|
startsWithWhitespace = startsWithWhitespace(buff); |
|
|
|
|
} else if (lastTextNode != null) { |
|
|
|
|
firstChar = lastTextNode.getText().charAt(0); |
|
|
|
|
startsWithWhitespace = startsWithWhitespace(lastTextNode.getText()); |
|
|
|
|
} else { |
|
|
|
|
startsWithWhitespace = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (Character.isWhitespace(firstChar)) { |
|
|
|
|
if (startsWithWhitespace) { |
|
|
|
|
writer.write(PAD_TEXT); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1066,15 +1065,14 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
if (format.isPadText()) { |
|
|
|
|
// only add the PAD_TEXT if the text itself ends
|
|
|
|
|
// with whitespace
|
|
|
|
|
char lastTextChar = 'a'; |
|
|
|
|
final boolean endsWithWhitespace; |
|
|
|
|
if (buff != null) { |
|
|
|
|
lastTextChar = buff.charAt(buff.length() - 1); |
|
|
|
|
} else if (lastTextNode != null) { |
|
|
|
|
String txt = lastTextNode.getText(); |
|
|
|
|
lastTextChar = txt.charAt(txt.length() - 1); |
|
|
|
|
endsWithWhitespace = endsWithWhitespace(buff); |
|
|
|
|
} else { |
|
|
|
|
endsWithWhitespace = endsWithWhitespace(lastTextNode.getText()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (Character.isWhitespace(lastTextChar)) { |
|
|
|
|
if (endsWithWhitespace) { |
|
|
|
|
writer.write(PAD_TEXT); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1091,14 +1089,14 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
if (!textOnly && format.isPadText()) { |
|
|
|
|
// only add the PAD_TEXT if the text itself starts with
|
|
|
|
|
// whitespace
|
|
|
|
|
char firstChar = 'a'; |
|
|
|
|
final boolean startsWithWhitespace; |
|
|
|
|
if (buff != null) { |
|
|
|
|
firstChar = buff.charAt(0); |
|
|
|
|
startsWithWhitespace = startsWithWhitespace(buff); |
|
|
|
|
} else { |
|
|
|
|
firstChar = lastTextNode.getText().charAt(0); |
|
|
|
|
startsWithWhitespace = startsWithWhitespace(lastTextNode.getText()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (Character.isWhitespace(firstChar)) { |
|
|
|
|
if (startsWithWhitespace) { |
|
|
|
|
writer.write(PAD_TEXT); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1115,9 +1113,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
} else { |
|
|
|
|
Node lastTextNode = null; |
|
|
|
|
|
|
|
|
|
for (int i = 0, size = element.nodeCount(); i < size; i++) { |
|
|
|
|
Node node = element.node(i); |
|
|
|
|
|
|
|
|
|
for (Node node : element.content()) { |
|
|
|
|
if (node instanceof Text) { |
|
|
|
|
writeNode(node); |
|
|
|
|
lastTextNode = node; |
|
|
|
@ -1125,10 +1121,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
if ((lastTextNode != null) && format.isPadText()) { |
|
|
|
|
// only add the PAD_TEXT if the text itself ends with
|
|
|
|
|
// whitespace
|
|
|
|
|
String txt = lastTextNode.getText(); |
|
|
|
|
char lastTextChar = txt.charAt(txt.length() - 1); |
|
|
|
|
|
|
|
|
|
if (Character.isWhitespace(lastTextChar)) { |
|
|
|
|
if (endsWithWhitespace(lastTextNode.getText())) { |
|
|
|
|
writer.write(PAD_TEXT); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1174,17 +1167,15 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the SAX namepsaces |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
|
protected void writeNamespaces() throws IOException { |
|
|
|
|
if (namespacesMap != null) { |
|
|
|
|
for (Iterator iter = namespacesMap.entrySet().iterator(); iter |
|
|
|
|
.hasNext();) { |
|
|
|
|
Map.Entry entry = (Map.Entry) iter.next(); |
|
|
|
|
String prefix = (String) entry.getKey(); |
|
|
|
|
String uri = (String) entry.getValue(); |
|
|
|
|
for (Map.Entry<String, String> entry : namespacesMap.entrySet()) { |
|
|
|
|
String prefix = entry.getKey(); |
|
|
|
|
String uri = entry.getValue(); |
|
|
|
|
writeNamespace(prefix, uri); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1194,15 +1185,15 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the SAX namepsaces |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param prefix |
|
|
|
|
* the prefix |
|
|
|
|
* @param uri |
|
|
|
|
* the namespace uri |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* |
|
|
|
|
* @throws IOException DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
|
protected void writeNamespace(String prefix, String uri) |
|
|
|
|
protected void writeNamespace(String prefix, String uri) |
|
|
|
|
throws IOException { |
|
|
|
|
if ((prefix != null) && (prefix.length() > 0)) { |
|
|
|
|
writer.write(" xmlns:"); |
|
|
|
@ -1216,6 +1207,19 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
writer.write("\""); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes all namespaces declared directly on element. |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
*/ |
|
|
|
|
protected void writeNamespaces(Element element) throws IOException { |
|
|
|
|
assert element != null; |
|
|
|
|
for (Namespace ns : element.declaredNamespaces()) { |
|
|
|
|
writeNamespace(ns); |
|
|
|
|
namespaceStack.push(ns); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected void writeProcessingInstruction(ProcessingInstruction pi) |
|
|
|
|
throws IOException { |
|
|
|
|
// indent();
|
|
|
|
@ -1259,12 +1263,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
writer.write(token); |
|
|
|
|
lastOutputNodeType = Node.TEXT_NODE; |
|
|
|
|
lastChar = token.charAt(token.length() - 1); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
lastOutputNodeType = Node.TEXT_NODE; |
|
|
|
|
writer.write(text); |
|
|
|
|
lastChar = text.charAt(text.length() - 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1272,10 +1274,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
/** |
|
|
|
|
* This method is used to write out Nodes that contain text and still allow |
|
|
|
|
* for xml:space to be handled properly. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param node |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -1289,7 +1291,6 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
lastOutputNodeType = Node.TEXT_NODE; |
|
|
|
|
writer.write(text); |
|
|
|
|
lastChar = text.charAt(text.length() - 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1362,9 +1363,9 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// try to register for lexical events
|
|
|
|
|
for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) { |
|
|
|
|
for (String lexicalHandlerName : LEXICAL_HANDLER_NAMES) { |
|
|
|
|
try { |
|
|
|
|
parent.setProperty(LEXICAL_HANDLER_NAMES[i], this); |
|
|
|
|
parent.setProperty(lexicalHandlerName, this); |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} catch (SAXNotRecognizedException ex) { |
|
|
|
@ -1434,10 +1435,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Writes the attributes of the given element |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param element |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -1481,26 +1482,24 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
writeNamespace(null, uri); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
char quote = format.getAttributeQuoteCharacter(); |
|
|
|
|
writer.write(" "); |
|
|
|
|
writer.write(attribute.getQualifiedName()); |
|
|
|
|
writer.write("="); |
|
|
|
|
writer.write(quote); |
|
|
|
|
writeEscapeAttributeEntities(attribute.getValue()); |
|
|
|
|
writer.write(quote); |
|
|
|
|
writeAttribute(attribute); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected void writeAttribute(Attribute attribute) throws IOException { |
|
|
|
|
writeAttribute(attribute.getQualifiedName(), attribute.getValue()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected void writeAttribute(String qualifiedName, String value) throws IOException { |
|
|
|
|
writer.write(" "); |
|
|
|
|
writer.write(attribute.getQualifiedName()); |
|
|
|
|
writer.write(qualifiedName); |
|
|
|
|
writer.write("="); |
|
|
|
|
|
|
|
|
|
char quote = format.getAttributeQuoteCharacter(); |
|
|
|
|
writer.write(quote); |
|
|
|
|
|
|
|
|
|
writeEscapeAttributeEntities(attribute.getValue()); |
|
|
|
|
writeEscapeAttributeEntities(value); |
|
|
|
|
|
|
|
|
|
writer.write(quote); |
|
|
|
|
lastOutputNodeType = Node.ATTRIBUTE_NODE; |
|
|
|
@ -1514,13 +1513,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
protected void writeAttribute(Attributes attributes, int index) |
|
|
|
|
throws IOException { |
|
|
|
|
char quote = format.getAttributeQuoteCharacter(); |
|
|
|
|
writer.write(" "); |
|
|
|
|
writer.write(attributes.getQName(index)); |
|
|
|
|
writer.write("="); |
|
|
|
|
writer.write(quote); |
|
|
|
|
writeEscapeAttributeEntities(attributes.getValue(index)); |
|
|
|
|
writer.write(quote); |
|
|
|
|
writeAttribute(attributes.getQName(index), attributes.getValue(index)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected void indent() throws IOException { |
|
|
|
@ -1537,29 +1530,26 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* <p> |
|
|
|
|
* This will print a new line only if the newlines flag was set to true |
|
|
|
|
* </p> |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
|
protected void writePrintln() throws IOException { |
|
|
|
|
if (format.isNewlines()) { |
|
|
|
|
String seperator = format.getLineSeparator(); |
|
|
|
|
if (lastChar != seperator.charAt(seperator.length() - 1)) { |
|
|
|
|
writer.write(format.getLineSeparator()); |
|
|
|
|
} |
|
|
|
|
writer.write(format.getLineSeparator()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get an OutputStreamWriter, use preferred encoding. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param outStream |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
* @param encoding |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @return DOCUMENT ME! |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws UnsupportedEncodingException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -1573,7 +1563,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* This will write the declaration to the given Writer. Assumes XML version |
|
|
|
|
* 1.0 since we don't directly know. |
|
|
|
|
* </p> |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @throws IOException |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
@ -1633,10 +1623,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* This will take the pre-defined entities in XML 1.0 and convert their |
|
|
|
|
* character representation to the appropriate entity reference, suitable |
|
|
|
|
* for XML attributes. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param text |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @return DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
|
protected String escapeElementEntities(String text) { |
|
|
|
@ -1647,44 +1637,37 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < size; i++) { |
|
|
|
|
String entity = null; |
|
|
|
|
char c = text.charAt(i); |
|
|
|
|
|
|
|
|
|
int c = text.codePointAt(i); |
|
|
|
|
switch (c) { |
|
|
|
|
case '<': |
|
|
|
|
entity = "<"; |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case '>': |
|
|
|
|
entity = ">"; |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case '&': |
|
|
|
|
entity = "&"; |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case '\t': |
|
|
|
|
case '\n': |
|
|
|
|
case '\r': |
|
|
|
|
|
|
|
|
|
// don't encode standard whitespace characters
|
|
|
|
|
if (preserve) { |
|
|
|
|
entity = String.valueOf(c); |
|
|
|
|
entity = String.valueOf((char) c); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
|
|
if ((c < 32) || shouldEncodeChar(c)) { |
|
|
|
|
entity = "&#" + (int) c + ";"; |
|
|
|
|
entity = "&#" + c + ";"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (entity != null) { |
|
|
|
|
if (block == null) { |
|
|
|
|
block = text.toCharArray(); |
|
|
|
@ -1693,6 +1676,12 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
buffer.append(block, last, i - last); |
|
|
|
|
buffer.append(entity); |
|
|
|
|
last = i + 1; |
|
|
|
|
if (Character.isSupplementaryCodePoint(c)) { |
|
|
|
|
last++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (Character.isSupplementaryCodePoint(c)) { |
|
|
|
|
i++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1725,10 +1714,10 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* This will take the pre-defined entities in XML 1.0 and convert their |
|
|
|
|
* character representation to the appropriate entity reference, suitable |
|
|
|
|
* for XML attributes. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param text |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @return DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
|
protected String escapeAttributeEntities(String text) { |
|
|
|
@ -1741,53 +1730,37 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < size; i++) { |
|
|
|
|
String entity = null; |
|
|
|
|
char c = text.charAt(i); |
|
|
|
|
int c = text.codePointAt(i); |
|
|
|
|
|
|
|
|
|
switch (c) { |
|
|
|
|
case '<': |
|
|
|
|
entity = "<"; |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case '>': |
|
|
|
|
entity = ">"; |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case '\'': |
|
|
|
|
|
|
|
|
|
if (quote == '\'') { |
|
|
|
|
entity = "'"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case '\"': |
|
|
|
|
|
|
|
|
|
if (quote == '\"') { |
|
|
|
|
entity = """; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case '&': |
|
|
|
|
entity = "&"; |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case '\t': |
|
|
|
|
case '\n': |
|
|
|
|
case '\r': |
|
|
|
|
|
|
|
|
|
// don't encode standard whitespace characters
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
|
|
if ((c < 32) || shouldEncodeChar(c)) { |
|
|
|
|
entity = "&#" + (int) c + ";"; |
|
|
|
|
entity = "&#" + c + ";"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1799,6 +1772,12 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
buffer.append(block, last, i - last); |
|
|
|
|
buffer.append(entity); |
|
|
|
|
last = i + 1; |
|
|
|
|
if(Character.isSupplementaryCodePoint(c)) { |
|
|
|
|
last++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(Character.isSupplementaryCodePoint(c)) { |
|
|
|
|
i++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1823,23 +1802,23 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
/** |
|
|
|
|
* Should the given character be escaped. This depends on the encoding of |
|
|
|
|
* the document. |
|
|
|
|
* |
|
|
|
|
* @param c |
|
|
|
|
* |
|
|
|
|
* @param codepoint Unicode codepoint. |
|
|
|
|
* DOCUMENT ME! |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @return boolean |
|
|
|
|
*/ |
|
|
|
|
protected boolean shouldEncodeChar(char c) { |
|
|
|
|
protected boolean shouldEncodeChar(int codepoint) { |
|
|
|
|
int max = getMaximumAllowedCharacter(); |
|
|
|
|
|
|
|
|
|
return (max > 0) && (c > max); |
|
|
|
|
return (max > 0) && (codepoint > max); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the maximum allowed character code that should be allowed |
|
|
|
|
* unescaped which defaults to 127 in US-ASCII (7 bit) or 255 in ISO- (8 |
|
|
|
|
* bit). |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @return DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
|
protected int defaultMaximumAllowedCharacter() { |
|
|
|
@ -1880,7 +1859,7 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* setTrimText, setNewLines, etc. Put in to support the HTMLWriter, in the |
|
|
|
|
* way that it pushes the current newline/trim state onto a stack and |
|
|
|
|
* overrides the state within preformatted tags. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @return DOCUMENT ME! |
|
|
|
|
*/ |
|
|
|
|
protected OutputFormat getOutputFormat() { |
|
|
|
@ -1900,24 +1879,24 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* 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 |
|
|
|
@ -1929,6 +1908,6 @@ public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
|
|
|
|
|
* 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. |
|
|
|
|
*/ |
|
|
|
|