All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.cq.commons.SimpleXml Maven / Gradle / Ivy

There is a newer version: 2024.11.18598.20241113T125352Z-241000
Show newest version
/*
 * Copyright 1997-2008 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */
package com.day.cq.commons;

import org.xml.sax.SAXException;
import org.xml.sax.Locator;
import org.xml.sax.helpers.AttributesImpl;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.TransformerException;
import javax.xml.transform.Transformer;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Stack;

/**
 * The SimpleXml class facilitates the creation of an XML document.
 */
public class SimpleXml {

    private boolean indentSet;
    private boolean encodingSet;
    private boolean inited;
    private PrintWriter writer;
    private TransformerHandler handler;
    private Transformer transformer;
    private StreamResult result;
    private Element currentElement;
    private Stack openElements;

    /**
     * Creates a SimpleXml instance using the specified
     * print writer for the output of the XML document.
     * @param w The writer to send the XML document to
     * @throws IOException If initialization fails
     */
    public SimpleXml(PrintWriter w) throws IOException {
        try {
            writer = w;
            handler = ((SAXTransformerFactory)SAXTransformerFactory.newInstance()).
                    newTransformerHandler();
            result = new StreamResult(writer);
            openElements = new Stack();
        } catch (TransformerException te) {
            throw new IOException(te.getMessage());
        }
    }

    /**
     * Returns the print writer used for the output of the XML document.
     * @return The print writer
     */
    public PrintWriter getWriter() {
        return writer;
    }

    /**
     * Defines whether the output should use indetation. Default is
     * true.
     * @param indent true if the output should use indentation,
     *               false otherwise
     * @return The XML writer
     */
    public SimpleXml setIndent(boolean indent) {
        getTransformer().setOutputProperty(OutputKeys.INDENT,
                indent? "yes" : "no");
        indentSet = true;
        return this;
    }

    /**
     * Sets the character encoding of the output. Default is UTF-8.
     * @param encoding The character encoding
     * @return The XML writer
     */
    public SimpleXml setEncoding(String encoding) {
        getTransformer().setOutputProperty(OutputKeys.ENCODING,
                encoding);
        encodingSet = true;
        return this;
    }

    /**
     * Defines whether the XML declaration should be omitted. Default is
     * false.
     * @param omit true if the XML declaration should be omitted,
     *             false otherwise
     * @return The XML writer
     */
    public SimpleXml omitXmlDeclaration(boolean omit) {
        getTransformer().setOutputProperty(
                OutputKeys.OMIT_XML_DECLARATION, omit ? "yes" : "no");
        return this;
    }

    /**
     * Sets the document locator of the output.
     * @param locator The document locator
     * @return The XML writer
     */
    public SimpleXml setDocumentLocator(Locator locator) {
        handler.setDocumentLocator(locator);
        return this;
    }

    /**
     * Opens the XML document. This method is a shorthand for
     * {@link #openDocument()}. 
     * @throws IOException If output fails
     * @return The XML writer
     */
    public SimpleXml open() throws IOException {
        return openDocument();
    }

    /**
     * Opens the XML document.
     * @throws IOException If output fails
     * @return The XML writer
     */
    public SimpleXml openDocument() throws IOException {
        if (!"yes".equals(getTransformer().getOutputProperty(
                OutputKeys.OMIT_XML_DECLARATION))) {
            init();
            try {
                handler.startDocument();
            } catch (SAXException se) {
                throw new IOException(se.getMessage());
            }
        }
        return this;
    }

    /**
     * Opens and returns a new XML element with the specified name.
     * @param name The name of the XML element
     * @return The XML element
     * @throws IOException If output fails
     */
    public Element open(String name) throws IOException {
        return open("", "", name);
    }

    /**
     * Opens and returns a new XML element with the specified name.
     * @param localName The local name of the XML element
     * @param name The name of the XML element
     * @return The XML element
     * @throws IOException If output fails
     */
    public Element open(String localName, String name) throws IOException {
        return open("", localName, name);
    }

    /**
     * Opens and returns a new XML element with the specified name.
     * @param uri The URI of the XML element
     * @param localName The local name of the XML element
     * @param name The name of the XML element
     * @return The XML element
     * @throws IOException If output fails
     */
    public Element open(String uri, String localName, String name)
            throws IOException {
        startElement(currentElement);
        currentElement = openElements.push(new Element(uri, localName, name));
        return currentElement;
    }

    /**
     * Opens and returns a new XML element with the specified name and content.
     * @param name The name of the XML element
     * @param content The content of the XML element
     * @param cdata true if content should be in a CDATA block,
     *              false otherwise
     * @return The XML element
     * @throws IOException If output fails
     */
    public Element open(String name, String content, boolean cdata)
            throws IOException {
        Element element = open("", "", name);
        element.setText(content, cdata);
        return element;
    }

    /**
     * Closes the XML document after closing all open elements.
     * @throws IOException If output fails
     */
    public void closeDocument() throws IOException {
        tidyUp();
        init();
        if (!"yes".equals(getTransformer().getOutputProperty(
                OutputKeys.OMIT_XML_DECLARATION))) {
            try {
                handler.endDocument();
            } catch (SAXException se) {
                throw new IOException(se.getMessage());
            }
        }
    }

    /**
     * Closes the most recent open element.
     * @throws IOException If output fails
     * @return The XML writer
     */
    public SimpleXml close() throws IOException {
        endElement(openElements.pop());
        return this;
    }

    /**
     * Closes all currently open elements.
     * @throws IOException If output fails
     * @return The XML writer
     */
    public SimpleXml tidyUp() throws IOException {
        while (!openElements.empty()) {
            Element element = openElements.pop();
            endElement(element);
        }
        return this;
    }

    /**
     * Initializes the output mechanism and sets defaults.
     */
    private void init() {
        if (!inited) {
            handler.setResult(result);
            if (!indentSet) {
                setIndent(true);
            }
            if (!encodingSet) {
                setEncoding("utf-8");
            }
            inited = true;
        }
    }

    /**
     * Returns the XML transformer.
     * @return The transformer
     */
    private Transformer getTransformer() {
        if (transformer == null) {
            transformer = handler.getTransformer();
        }
        return transformer;
    }

    /**
     * Starts the output of the specified XML element.
     * @param element The XML element
     * @throws IOException If output fails
     */
    private void startElement(Element element) throws IOException {
        if (element == null) {
            return;
        }
        if (!element.isOpened()){
            init();
            try {
                String uri = element.getUri();
                String localName = element.getLocalName();
                String name = element.getName();
                AttributesImpl atts = element.getAttributes();
                handler.startElement(uri, localName, name, atts);
            } catch (SAXException se) {
                throw new IOException(se.getMessage());
            }
            element.setOpened(true);
        }
    }

    /**
     * Ends the output of the specified XML element, removing it from
     * the list of open elements.
     * @param element The XML element
     * @throws IOException If output fails
     */
    private void endElement(Element element) throws IOException {
        if (element == null) {
            return;
        }
        if (!element.isClosed()) {
            startElement(element); // make sure element is started
            init();
            try {
                String uri = element.getUri();
                String localName = element.getLocalName();
                String name = element.getName();
                String content = element.getText();
                if (content != null) {
                    if (element.hasCDATA()) {
                        handler.startCDATA();
                    }
                    handler.characters(content.toCharArray(), 0,
                            content.length());
                    if (element.hasCDATA()) {
                        handler.endCDATA();
                    }
                }
                handler.endElement(uri, localName, name);
            } catch (SAXException se) {
                throw new IOException(se.getMessage());
            }
            element.setClosed(true);
            currentElement = null;
        }
        openElements.remove(element);
    }

    /**
     * The SimpleXml.Element reperesents an XML element.
     */
    public class Element {

        private boolean opened;
        private boolean closed;
        private boolean cdata;
        private AttributesImpl atts;
        private String uri;
        private String localName;
        private String name;
        private String text;

        /**
         * Creates a new 
SimpleXML.Element
instance using the * specified URI, local name and name. * @param uri The URI of the XML element * @param localName The local name of the XML element * @param name The name of the XML element */ protected Element(String uri, String localName, String name) { this.uri = uri; this.localName = localName; this.name = name; atts = new AttributesImpl(); } /** * Adds a new attribute to the XML element. This method is a shorthand * for {@link #addAttribute(String, String, String, String, String)}. * @param name The name of the attribute * @param value The value of the attribute * @return The XML element */ public Element attr(String name, String value) { return attr("", "", name, value, "CDATA"); } /** * Adds a new attribute to the XML element. This method is a shorthand * for {@link #addAttribute(String, String, String, String, String)}. * @param localName The local name of the attribute * @param name The name of the attribute * @param value The value of the attribute * @return The XML element */ public Element attr(String localName, String name, String value) { return attr("", localName, name, value, "CDATA"); } /** * Adds a new attribute to the XML element. This method is a shorthand * for {@link #addAttribute(String, String, String, String, String)}. * @param uri The URI of the attribute * @param localName The local name of the attribute * @param name The name of the attribute * @param value The value of the attribute * @param type The type of the attribute * @return The XML element */ public Element attr(String uri, String localName, String name, String value, String type) { return addAttribute(uri, localName, name, value, type); } /** * Adds the specified attributes to the XML element. * @param atts The attributes * @return The XML element */ public Element attrs(String[] ... atts) { for (int i = 0; i < atts.length; i++) { attr(atts[i][0], atts[i][1]); } return this; } /** * Adds a new attribute to the XML element. * @param uri The URI of the attribute * @param localName The local name of the attribute * @param name The name of the attribute * @param value The value of the attribute * @param type The type of the attribute * @return The XML element */ public Element addAttribute(String uri, String localName, String name, String value, String type) { if (!opened) { atts.addAttribute(uri, localName, name, type, value); } return this; } /** * Sets the content of the XML element. This method is a shorthand * for {@link #setText(String, boolean)}. * @param text The content * @return The XML element */ public Element text(String text) { return text(text, false); } /** * Sets the content of the XML element. This method is a shorthand * for {@link #setText(String, boolean)}. * @param text The content * @param cdata true if content should be in a CDATA block, * false otherwise * @return The XML element */ public Element text(String text, boolean cdata) { return setText(text, cdata); } /** * Sets the content of the XML element. * @param text The content * @param cdata true if content should be in a CDATA block, * false otherwise * @return The XML element */ public Element setText(String text, boolean cdata) { if (!closed) { this.text = text; this.cdata = cdata; } return this; } /** * Defines whether the XML element has a CDATA block. * @param cdata true if the XML element has a CDATA block, * false otherwise * @return The XML element */ public Element setCDATA(boolean cdata) { if (!closed) { this.cdata = cdata; } return this; } /** * Explicitly opens the XML element. No more attributes can be added * to the XML element after calling this method. * @return The XML writer * @throws IOException If output fails */ public SimpleXml open() throws IOException { if (!opened) { startElement(this); } return getWriter(); } /** * Opens and returns a new XML element with the specified name. * This method can be used for chaining. It opens the current XML * element, then calls its equivalent in {@link SimpleXml}. * @see SimpleXml#open(String) * @param name The name of the XML element * @return The XML element * @throws IOException If output fails */ public Element open(String name) throws IOException { open(); return getWriter().open(name); } /** * Opens and returns a new XML element with the specified name. * This method can be used for chaining. It opens the current XML * element, then calls its equivalent in {@link SimpleXml}. * @see SimpleXml#open(String, String) * @param localName The local name of the XML element * @param name The name of the XML element * @return The XML element * @throws IOException If output fails */ public Element open(String localName, String name) throws IOException { open(); return getWriter().open(localName, name); } /** * Opens and returns a new XML element with the specified name. * This method can be used for chaining. It opens the current XML * element, then calls its equivalent in {@link SimpleXml}. * @see SimpleXml#open(String, String, String) * @param uri The URI of the XML element * @param localName The local name of the XML element * @param name The name of the XML element * @return The XML element * @throws IOException If output fails */ public Element open(String uri, String localName, String name) throws IOException { open(); return getWriter().open(uri, localName, name); } /** * Opens and returns a new XML element with the specified name and content. * This method can be used for chaining. It opens the current XML * element, then calls its equivalent in {@link SimpleXml}. * @see SimpleXml#open(String, String, boolean) * @param name The name of the XML element * @param content The content of the XML element * @param cdata true if content should be in a CDATA block, * false otherwise * @return The XML element * @throws IOException If output fails */ public Element open(String name, String content, boolean cdata) throws IOException { open(); return getWriter().open(name, content, cdata); } /** * Explicitly closes the XML element. This method will write the * XML element and consequently render it immutable. * @return The XML writer * @throws IOException If output fails */ public SimpleXml close() throws IOException { if (!closed) { endElement(this); } return getWriter(); } /** * States whether the XML element has a CDATA block. * @return true if the XML element has a CDATA block, * false otherwise */ public boolean hasCDATA() { return cdata; } /** * Returns the underlying XML writer * @return The XML writer */ protected SimpleXml getWriter() { return SimpleXml.this; } /** * States whether the output of the XML element has been started. * @return true if the output has been started, * false otherwise */ protected boolean isOpened() { return opened; } /** * Defines whether the output of the XML element has been started. * @param opened true if the output has been started, * false otherwise */ protected void setOpened(boolean opened) { this.opened = opened; } /** * States whether the output of the XML element has been ended. * @return true if the output has been ended, * false otherwise */ protected boolean isClosed() { return closed; } /** * Defines whether the output of the XML element has been ended. * @param closed true if the output has been ended, * false otherwise */ protected void setClosed(boolean closed) { this.closed = closed; } /** * Returns the attributes of the XML element. * @return The attributes */ protected AttributesImpl getAttributes() { return atts; } /** * Returns the URI of the XML element. * @return The URI */ protected String getUri() { return uri; } /** * Returns the local name of the XML element. * @return The local name */ protected String getLocalName() { return localName; } /** * Returns the name of the XML element. * @return The name */ protected String getName() { return name; } /** * Returns the content of the XML element. * @return The content */ protected String getText() { return text; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy