/** * Copyright 2007-2008 University Of Southern California * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.isi.pegasus.common.util; import java.io.IOException; import java.io.Writer; import java.util.Stack; import edu.isi.pegasus.common.logging.LogManager; import edu.isi.pegasus.common.logging.LogManagerFactory; /** * * @author gmehta */ public class XMLWriter { private Writer mWriter; private Stack<String> mStack; private StringBuffer mAttributes; private boolean mEmptyElement; private boolean mClosedElement; private boolean mWriteLine = true; private boolean mHeader = true; private LogManager mLogger; private static String START_ELEMENT_TAG = "<"; private static String CLOSE_ELEMENT_TAG = ">"; private static String START_END_ELEMENT_TAG = "</"; private static String CLOSE_EMPTY_ELEMENT_TAG = "/>"; private static String START_COMMENT_TAG = "<!-- "; private static String CLOSE_COMMENT_TAG = " -->"; private static String INDENT = " "; private static String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; private String mLineSeparator; private String mNamespace; public XMLWriter(Writer writer) { this(writer, ""); } public XMLWriter(Writer writer, String namespace) { mWriter = writer; mNamespace = (namespace == null) ? "" : namespace; mStack = new Stack<String>(); mAttributes = new StringBuffer(); mClosedElement = true; mLogger = LogManagerFactory.loadSingletonInstance(); mLineSeparator = System.getProperty("line.separator", "\r\n"); this.writeXMLHeader(); this.writeXMLComment("generated on: " + Currently.iso8601(false)); this.writeXMLComment("generated by: " + System.getProperties().getProperty("user.name", "unknown") + " [ " + System.getProperties().getProperty("user.region", "??") + " ]"); } public XMLWriter startElement(String name) { startElement(name, 0); return this; } public XMLWriter startElement(String name, int indent) { try { //check if there are any previous elements open and close them closeElement(); indent(indent); mClosedElement = false; mWriter.write(START_ELEMENT_TAG); if (!mNamespace.isEmpty()) { mWriter.write(mNamespace + ":"); } mWriter.write(name); } catch (IOException ioe) { mLogger.log("Could not write element " + name + "using XMLWriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } mStack.add(name); mEmptyElement = true; return this; } public XMLWriter endElement() { endElement(0); return this; } public XMLWriter endElement(int indent) { if (mStack.empty()) { mLogger.log("No elements left to close", LogManager.WARNING_MESSAGE_LEVEL); } String element = mStack.pop(); try { if (element != null) { if (mEmptyElement) { writeAttributes(); mWriter.write(CLOSE_EMPTY_ELEMENT_TAG); if (mWriteLine) { writeLine(); } // mEmptyElement=false; } else { indent(indent); mWriter.write(START_END_ELEMENT_TAG); if (!mNamespace.isEmpty()) { mWriter.write(mNamespace + ":"); } mWriter.write(element); mWriter.write(CLOSE_ELEMENT_TAG); if (mWriteLine) { writeLine(); } } mClosedElement = true; mEmptyElement = false; mWriteLine = true; } } catch (IOException ioe) { mLogger.log( "Could not close element " + element + "using XMLWriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } return this; } public XMLWriter writeData(String data) { try { mEmptyElement = false; closeElement(); mWriter.write(escapeXML(data)); } catch (IOException ioe) { mLogger.log( "Could not write data for element " + mStack.peek() + " using XMLWriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } return this; } public XMLWriter writeUnEscapedData(String data) { try { mEmptyElement = false; closeElement(); mWriter.write(data); } catch (IOException ioe) { mLogger.log( "Could not write data for element " + mStack.peek() + " using XMLWriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } return this; } public XMLWriter writeLine() { try { mWriter.write(mLineSeparator); } catch (IOException ioe) { mLogger.log( "Could not write empty line using XMLWriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } return this; } public XMLWriter noLine() { mWriteLine = false; return this; } public XMLWriter writeCData(String data) { try { mEmptyElement = false; closeElement(); mWriter.write("<![CDATA["); mWriter.write(data); mWriter.write("]]>"); } catch (IOException ioe) { mLogger.log( "Could not write data for element " + mStack.peek() + " using XMLWriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } return this; } public XMLWriter writeAttribute(String key, String value) { mAttributes.append(" "); if (!mNamespace.isEmpty()) { mAttributes.append(mNamespace).append(":"); } mAttributes.append(key).append("=\"").append( escapeXML(value)).append("\""); return this; } /** * Writes out the attributes of a given element to the writer */ private void writeAttributes() { try { mWriter.write(mAttributes.toString()); mAttributes.setLength(0); } catch (IOException ioe) { mLogger.log( "Could not write attributes for element " + mStack.peek() + " using XMLWriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } } /** * Close open elements start tag. Write any attributes. * This is called when either a new child element is added to existing element or data is added. * @return XMLWriter */ private void closeElement() { try { if (!mClosedElement) { writeAttributes(); mClosedElement = true; mWriter.write(CLOSE_ELEMENT_TAG); if (mEmptyElement) { writeLine(); } } } catch (IOException ioe) { mLogger.log( "Could not close open element " + mStack.peek() + " using XMLWriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } } public XMLWriter writeXMLHeader() { if (mHeader) { try { mWriter.write(XML_HEADER); writeLine(); mHeader = true; } catch (IOException ioe) { mLogger.log( "Could not write xml header using XMLWriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } } return this; } public XMLWriter writeXMLComment(String comment, boolean linepadded) { try { closeElement(); if (linepadded) { writeLine(); } mWriter.write(START_COMMENT_TAG); mWriter.write(comment); mWriter.write(CLOSE_COMMENT_TAG); writeLine(); if (linepadded) { writeLine(); } } catch (IOException ioe) { mLogger.log( "Could not write xml comment using XMLWriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } return this; } public XMLWriter writeXMLComment(String comment) { this.writeXMLComment(comment, false); return this; } private XMLWriter indent(int indent) { try { mWriter.write( (indent <= 0) ? "" : String.format(String.format("%%0%dd", indent), 0).replace("0", INDENT)); } catch (IOException ioe) { mLogger.log( "Could not write xml comment using XMLWriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } return this; } private static String escapeXML(String str) { String st = str; st = st.replaceAll("&", "&"); st = st.replaceAll("<", "<"); st = st.replaceAll(">", ">"); st = st.replaceAll("\"", """); st = st.replaceAll("'", "'"); return st; } public void close() { try { mWriter.close(); } catch (IOException ioe) { mLogger.log( "Could not close XMLwriter", LogManager.ERROR_MESSAGE_LEVEL); mLogger.log(ioe.getMessage(), LogManager.DEBUG_MESSAGE_LEVEL); } } }