/**
* 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);
}
}
}