/* * � Copyright IBM Corp. 2010 * * 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 com.ibm.domino.services.util; import java.io.IOException; import java.io.Writer; import java.text.SimpleDateFormat; import java.util.Date; import lotus.domino.DateTime; import lotus.domino.NotesException; import com.ibm.commons.util.AbstractIOException; import com.ibm.domino.services.rest.RestServiceConstants; import static com.ibm.domino.services.HttpServiceConstants.*; /** * Specialized XML writer. * * @author Philippe Riand */ public class XmlWriter { private static final int CONTENT_NONE = 0; private static final int CONTENT_TEXT = 1; private static final int CONTENT_TAG = 2; private Writer writer; private boolean compact; private int indentLevel; private boolean inElement; private int hasContent; public XmlWriter(Writer writer, boolean compact) { this.writer = writer; this.compact = compact; } public void flush() throws IOException { writer.flush(); } public void close() throws IOException { writer.close(); } public int getIndentLevel() { return indentLevel; } public void setIndentLevel(int indentLevel) { this.indentLevel = indentLevel; } public void incIndent() { indentLevel++; } public void decIndent() { indentLevel--; } public boolean isCompact() { return compact; } public void writeDecl(String encoding) throws IOException { out("<?xml version=\"1.0\" encoding=\""); // $NON-NLS-1$ out(encoding); out("\"?>"); } public void out(char c) throws IOException { writer.write(c); } public void out(String s) throws IOException { writer.write(s); } public void startElement(String elementName) throws IOException { if(inElement) { closeElement(); } nl(); indent(); out('<'); out(elementName); incIndent(); inElement = true; hasContent = CONTENT_NONE; } public void closeElement() throws IOException { if(inElement) { out('>'); inElement = false; } } public void endElement(String elementName) throws IOException { if(inElement) { closeElement(); } decIndent(); if(hasContent==CONTENT_TAG) { nl(); indent(); } out('<'); out('/'); out(elementName); out('>'); hasContent = CONTENT_TAG; } public void writeAttribute(String name, String value) throws IOException { out(' '); out(name); out('='); out('"'); out(toXMLString(value)); out('"'); } public void writeAttribute(String name, int value) throws IOException { out(' '); out(name); out('='); out('"'); out(Integer.toString(value)); out('"'); } public void writeAttribute(String name, long value) throws IOException { out(' '); out(name); out('='); out('"'); out(Long.toString(value)); out('"'); } public void writeAttribute(String name, boolean value) throws IOException { out(' '); out(name); out('='); out('"'); out(Boolean.toString(value)); out('"'); } public void writeAttribute(String name, double value) throws IOException { out(' '); out(name); out('='); out('"'); out(Double.toString(value)); out('"'); } public void writeAttribute(String name, Date value) throws IOException { out(' '); out(name); out('='); out('"'); out(dateToString(value)); out('"'); } public void writeAttribute(String name, DateTime value) throws IOException { out(' '); out(name); out('='); out('"'); out(dateToString(value)); out('"'); } public void writeText(String text) throws IOException { if(inElement) { closeElement(); } out(toXMLString(text)); if(hasContent!=CONTENT_TAG) { hasContent = CONTENT_TEXT; } } public void writeInt(int value) throws IOException { if(inElement) { closeElement(); } out(Integer.toString(value)); if(hasContent!=CONTENT_TAG) { hasContent = CONTENT_TEXT; } } public void writeLong(long value) throws IOException { if(inElement) { closeElement(); } out(Long.toString(value)); if(hasContent!=CONTENT_TAG) { hasContent = CONTENT_TEXT; } } public void writeNumber(double value) throws IOException { if(inElement) { closeElement(); } long l = (long)value; if((double)l==value) { out(Long.toString(l)); } else { out(Double.toString(value)); } if(hasContent!=CONTENT_TAG) { hasContent = CONTENT_TEXT; } } public void writeBoolean(boolean value) throws IOException { if(inElement) { closeElement(); } out(Boolean.toString(value)); if(hasContent!=CONTENT_TAG) { hasContent = CONTENT_TEXT; } } public void writeDate(Date value) throws IOException { if(inElement) { closeElement(); } out(dateToString(value)); if(hasContent!=CONTENT_TAG) { hasContent = CONTENT_TEXT; } } public void writeDate(DateTime value) throws IOException { if(inElement) { closeElement(); } out(dateToString(value)); if(hasContent!=CONTENT_TAG) { hasContent = CONTENT_TEXT; } } protected static String toXMLString(String s) { if( s==null ) { return null; } StringBuilder b = null; char[] chars = s.toCharArray(); int length = chars.length; for( int i=0; i<length; i++ ) { char c = chars[i]; // Is it a specific entity ? switch(c) { case '&': case '\'': case '>': case '<': case '\"': { if( b==null ) { b = new StringBuilder(); b.append(s, 0, i); } if( c=='&' ) { b.append( HTML_AMP ); break; } //$NON-NLS-1$ if( c=='\'' ) { b.append( HTML_APOS ); break; } //$NON-NLS-1$ if( c=='>' ) { b.append( HTML_GT ); break; } //$NON-NLS-1$ if( c=='<' ) { b.append( HTML_LT ); break; } //$NON-NLS-1$ if( c=='\"' ) { b.append( HTML_QUOT ); break; } //$NON-NLS-1$ } break; default: { if( b!=null ) { b.append(c); } } } } return b!=null ? b.toString() : s; } public void indent() throws IOException { if(!compact && indentLevel>0) { for(int i=0; i<indentLevel; i++) { out(" "); } } } public void nl() throws IOException { if(!compact) { out('\n'); } } //TODO: What the TZ should be?? private static SimpleDateFormat ISO8601 = new SimpleDateFormat(RestServiceConstants.TIME_FORMAT_B); //$NON-NLS-1$ public String dateToString(Date value) throws IOException { return ISO8601.format((Date)value); } public String dateToString(DateTime value) throws IOException { try { return ISO8601.format(((DateTime)value).toJavaDate()); } catch(NotesException ex) { throw new AbstractIOException(ex,""); } } public Date toJavaDate(DateTime value) throws IOException { try { return value.toJavaDate(); } catch(NotesException ex) { throw new AbstractIOException(ex,""); } } }