[jdom-interest] PATCH: XMLOutputter refactoring/opening

Alex Chaffee guru at edamame.stinky.com
Fri Sep 29 06:28:01 PDT 2000


I've patched XMLOutputter to make the following changes.  Please
integrate these into the version in the repository.

Added trimText property: will set whether the text is output verbatim
(false) or with whitespace stripped as per Element.getTextTrim().
Default: false

Updated documentation slightly

Made methods to print the inside of documents public, to wit:
  printComment
  printProcessingInstruction
  printDeclaration
  printDocType
  printCDATASection
  printElement

Made clean convenience wrappers for a few of the above; the rest take
indent parameters (which can be 0).

Refactored printElement so it calls printElementContent; slighly
cleaner if-then-else logic.

Made printElementContent public, in case you want to print just the
content of an element, and not the open/close tags.  (Believe it or
not, I had a need for this: printing an element whose content is an
HTML snippet, which could be mixed/nested content.)

Needs a bit of testing, esp. with namespaces (I'm no good at namespaces).

[Note: the setIndenting method seems redundant with setIndent(null) or
setIndent("") -- let's remove it?]

----------------

bash.exe-2.02$ cvs diff -u src/java/org/jdom/output/XMLOutputter.java
Index: src/java/org/jdom/output/XMLOutputter.java
===================================================================
RCS file: /home/cvspublic/jdom/src/java/org/jdom/output/XMLOutputter.java,v
retrieving revision 1.21
diff -u -r1.21 XMLOutputter.java
--- src/java/org/jdom/output/XMLOutputter.java	2000/09/20 00:30:40	1.21
+++ src/java/org/jdom/output/XMLOutputter.java	2000/09/29 13:41:21
@@ -97,6 +97,7 @@
  * @author Elliotte Rusty Harold
  * @author David & Will (from Post Tool Design)
  * @author Dan Schaffer
+ * @author Alex Chaffee (alex at jguru.com)
  * @version 1.0
  */
 public class XMLOutputter {
@@ -125,6 +126,9 @@
     /** New line separator */
     private String newline = "\r\n";
 
+    /** should we preserve whitespace or not? */
+    private boolean trimText = false;
+
     /**
      * <p>
      * This will create an <code>XMLOutputter</code> with
@@ -189,6 +193,16 @@
      * <p>
      *  This will set the new-line separator. The default is <code>\r\n</code>.
      * </p>
+     * <blockquote>
+     *  We could change this to the System default, 
+     *  but I prefer not to make output platform dependent.
+     *  A carriage return, linefeed pair is the most generally
+     *  acceptable linebreak.  Another possibility is to use
+     *  only a line feed, which is XML's preferred (but not required)
+     *  solution. However both carriage return and linefeed are
+     *  required for many network protocols, and the parser on the
+     *  other end should normalize this.  --Rusty
+     * </blockquote>
      *
      * @param separator <code>String</code> line separator to use.
      */
@@ -239,6 +253,17 @@
 
     /**
      * <p>
+     *  This will set whether the text is output verbatim (false) or with whitespace stripped as per Element.getTextTrim().  Default: false;
+     * </p>
+     *
+     * @param trimText <code>boolean</code> true=>trim the whitespace, false=>use text verbatim
+     */
+    public void setTrimText(boolean trimText) {
+        this.trimText = trimText;
+    }
+
+    /**
+     * <p>
      *   This will set the indent <code>String</code> to use; this is usually
      *    a <code>String</code> of empty spaces. Note that this will not affect the
      *    output if no indentation is being used. This can be set through
@@ -381,7 +406,7 @@
      * @param out <code>Writer</code> to write to.
      * @param indentLevel Current depth in hierarchy.
      */
-    protected void printComment(Comment comment,
+    public void printComment(Comment comment,
                                     Writer out, int indentLevel) throws IOException {
                                         
         indent(out, indentLevel);
@@ -399,7 +424,7 @@
      * @param out <code>Writer</code> to write to.
      * @param indentLevel Current depth in hierarchy.
      */
-    protected void printProcessingInstruction(ProcessingInstruction pi,
+    public void printProcessingInstruction(ProcessingInstruction pi,
                                     Writer out, int indentLevel) throws IOException {
                                         
         indent(out, indentLevel);
@@ -418,7 +443,7 @@
      * @param docType <code>DocType</code> whose declaration to write.
      * @param out <code>Writer</code> to write to.
      */
-    protected void printDeclaration(Document doc,
+    public void printDeclaration(Document doc,
                                     Writer out,
                                     String encoding)  throws IOException {
 
@@ -452,7 +477,7 @@
      * @param doc <code>Document</code> whose declaration to write.
      * @param out <code>Writer</code> to write to.
      */
-    protected void printDocType(DocType docType, Writer out)  throws IOException {
+    public void printDocType(DocType docType, Writer out)  throws IOException {
         if (docType == null) {
             return;
         }
@@ -491,7 +516,7 @@
      * @param out <code>Writer</code> to write to.
      * @param indent <code>int</code> level of indention.
      */
-    protected void printCDATASection(CDATA cdata,
+    public void printCDATASection(CDATA cdata,
 			      Writer out, int indentLevel) throws IOException {
 	
         indent(out, indentLevel);
@@ -503,14 +528,31 @@
     /**
      * <p>
      * This will handle printing out an <code>{@link Element}</code>,
-     *   its <code>{@link Attribute}</code>s, and its value.
+     *   its <code>{@link Attribute}</code>s, and its value, and all
+     *   contained (child) elements etc.
+     * </p>
+     *
+     * @param element <code>Element</code> to output.
+     * @param out <code>Writer</code> to write to.
+     **/
+    public void printElement(Element element, Writer out)
+	throws IOException
+    {
+	printElement(element, out, 0);
+    }
+    
+    /**
+     * <p>
+     * This will handle printing out an <code>{@link Element}</code>,
+     *   its <code>{@link Attribute}</code>s, and its value, and all
+     *   contained (child) elements etc.
      * </p>
      *
      * @param element <code>Element</code> to output.
      * @param out <code>Writer</code> to write to.
      * @param indent <code>int</code> level of indention.
      */
-    protected void printElement(Element element, Writer out,
+    public  void printElement(Element element, Writer out,
                                 int indentLevel)  throws IOException {
                                         
         // if this is the root element we could pre-initialize the namespace stack
@@ -565,6 +607,16 @@
 
         printAttributes(element.getAttributes(), element, out, namespaces);
 
+	// handle "" string same as empty
+	if (stringOnly) {
+            String elementText =
+		trimText ? element.getTextTrim() : element.getText();
+	    if (elementText == null ||
+		elementText.equals("")) {
+		empty = true;
+	    }
+	}
+	
         if (empty) {
             // Simply close up
             if (!expandEmptyElements) {
@@ -574,28 +626,79 @@
                 out.write(element.getQualifiedName());
                 out.write(">");
             }
+            maybePrintln(out);
+        } else {
+	    // we know it's not null or empty from above
+	    out.write(">");
+
+	    if (stringOnly) {
+		// if string only, print content on same line as tags
+		printElementContent(element, out, indentLevel, namespaces, mixedContent);
+	    }
+	    else {
+		maybePrintln(out);
+		printElementContent(element, out, indentLevel, namespaces, mixedContent);
+		indent(out, indentLevel);		
+	    }
+
+	    out.write("</");
+	    out.write(element.getQualifiedName());
+	    out.write(">");
+
             maybePrintln(out);
-        } else if (stringOnly) {
+	}
+
+	// remove declared namespaces from stack
+	while (namespaces.size() > previouslyDeclaredNamespaces) namespaces.pop();
+    }
+    
+    /**
+     * <p> This will handle printing out an <code>{@link
+     * Element}</code>'s content only, not including its tag,
+     * attributes, and namespace info.  </p>
+     *
+     * @param element <code>Element</code> to output.
+     * @param out <code>Writer</code> to write to.
+     * @param indent <code>int</code> level of indention.  */
+    public void printElementContent(Element element, Writer out)
+	throws IOException
+    {
+        List mixedContent = element.getMixedContent();
+	printElementContent(element, out, 0,
+			    new NamespaceStack(),
+			    mixedContent);
+    }
+
+    /**
+     * <p> This will handle printing out an <code>{@link
+     * Element}</code>'s content only, not including its tag,
+     * attributes, and namespace info.  </p>
+     *
+     * @param element <code>Element</code> to output.
+     * @param out <code>Writer</code> to write to.
+     * @param indent <code>int</code> level of indention.  */
+    protected void printElementContent(Element element, Writer out,
+				       int indentLevel,
+				       NamespaceStack namespaces,
+				       List mixedContent
+				       )  throws IOException
+    {
+	// get same local flags as printElement does
+	// a little redundant code-wise, but not performance-wise
+        boolean empty = mixedContent.size() == 0;
+        boolean stringOnly =
+            !empty &&
+            (mixedContent.size() == 1) &&
+            mixedContent.get(0) instanceof String;
+
+	if (stringOnly) {
             // Print the tag  with String on same line
             // Example: <tag name="value">content</tag>
-            // Also handle "" being added to content
-            String elementText = element.getText();
-            if ((elementText != null) && (!elementText.equals(""))) {
-                out.write(">");
-                out.write(escapeElementEntities(element.getText()));
-                out.write("</");
-                out.write(element.getQualifiedName());
-                out.write(">");
-            } else {
-                if (!expandEmptyElements) {     
-                    out.write(" />");
-                } else {
-                    out.write("></");
-                    out.write(element.getQualifiedName());
-                    out.write(">");
-                }
-            }
-            maybePrintln(out);
+            String elementText =
+		trimText ? element.getTextTrim() : element.getText();
+	    
+	    out.write(escapeElementEntities(elementText));
+	    
         } else {
             /**
              * Print with children on future lines
@@ -604,8 +707,6 @@
              *             <child/>
              *          </tag>
              */
-            out.write(">");
-            maybePrintln(out);
             // Iterate through children
             Object content = null;
             for (int i=0, size=mixedContent.size(); i<size; i++) {
@@ -626,19 +727,9 @@
                 } // Unsupported types are *not* printed
             }
 
-            indent(out, indentLevel);
-            out.write("</");
-            out.write(element.getQualifiedName());
-            out.write(">");
-            maybePrintln(out);
-
         }
+    }  // printElementContent
 
-        // remove declared namespaces from stack
-        while (namespaces.size() > previouslyDeclaredNamespaces) namespaces.pop();
-        
-    }
-    
     /**
      * <p>
      * This will handle printing out an <code>{@link Entity}</code>.



More information about the jdom-interest mailing list