Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Format XML, one attribute per line, with JDom

I use JDom for XML parsing / formatting. I would like long lines of attributes to be split into several lines.

Like :

<node att1="Foo" att2="Bar" att3="Foo" />

Into :

<node
     att1="Foo"
     att2="Bar"
     att3="Foo" />

According to the JDom FAQ, JDom can be transformed into standard DOM and SAX events. So any renderer that supports SAX or DOM and is capable of such pretty rendering would be great.

Thanks in advance.

like image 842
Raphael Jolivet Avatar asked Aug 03 '11 08:08

Raphael Jolivet


1 Answers

Ok, I didn't find any class that did that. So I implemented one myself as a sub class of org.jdom.output.XMLOutputter

import java.io.IOException;
import java.io.Writer;
import java.util.*;

import org.jdom.Attribute;
import org.jdom.Element;
import org.jdom.output.XMLOutputter;


/** This outputter prints each attributes in a new line */
public class OneAttributePerLineOutputter extends XMLOutputter {

    // ----------------------------------------------------
    // Attribute
    // ----------------------------------------------------

    /** Limit wrapping attribute for one namespace */
    String namespace = null;

    /** Number of inline attributes before wrapping */
    private int nbInlineAttribs;

    // ----------------------------------------------------
    // Constructor
    // ----------------------------------------------------

    /**
     * @param namespace Limit wrapping attributes to one namespace. If null, all attributes are concerned
     * @param nbInlineAttribs Allow a given number of inline elements before wrapping to several lines 
     */
    public OneAttributePerLineOutputter(
            String namespace,
            int nbInlineAttribs) 
    {
        this.namespace = namespace;
        this.nbInlineAttribs = nbInlineAttribs;
    }

    // ----------------------------------------------------
    // Helpers
    // ----------------------------------------------------

    static private int elementDepth(Element element) {
        int result = 0;
        while(element != null) {
            result++;
            element = element.getParentElement();
        }
        return result;
    }

    // ----------------------------------------------------
    // Overridden methods
    // ----------------------------------------------------

    @Override protected void printAttributes(
            Writer writer, 
            List attribs, 
            Element parent,
            NamespaceStack ns) throws IOException 
    {       
                    // Loop on attributes
            for (Object attribObj : attribs) {

                Attribute attrib = (Attribute) attribObj;

                // Check namespace
                if ((this.namespace == null) || 
                    (this.namespace.equals(attrib.getNamespaceURI()))) 
                {   
                    // Reached max number of inline attribs ? 
                    if (attribs.size() > this.nbInlineAttribs) {

                        // New line
                        writer.append("\n");

                        // Indent
                        for (int i=0; i < elementDepth(parent); i++) {
                            writer.append(this.getFormat().getIndent());
                        }
                    }
                }

                // Output single atribute 
                List list = new ArrayList<Object>();
                list.add(attrib);
                super.printAttributes(writer, list, parent, ns);
            }
    }
}

This serializer will follow the indent policy of the given Format.

It allows to apply attribute wrapping to a single namespace only (I needed that feature) and you can specify the maximum number of inline attributes you allow before it wraps them.

I hope this can be useful to someone.

like image 147
Raphael Jolivet Avatar answered Oct 06 '22 06:10

Raphael Jolivet