-/*\r * Copyright \r * 2005 axYus - www.axyus.com\r * 2005 C.Marchand - christophe.marchand@axyus.com\r * \r * This file is part of XEMELIOS.\r * \r * XEMELIOS is free software; you can redistribute it and/or modify\r * it under the terms of the GNU General Public License as published by\r * the Free Software Foundation; either version 2 of the License, or\r * (at your option) any later version.\r * \r * XEMELIOS is distributed in the hope that it will be useful,\r * but WITHOUT ANY WARRANTY; without even the implied warranty of\r * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r * GNU General Public License for more details.\r * \r * You should have received a copy of the GNU General Public License\r * along with XEMELIOS; if not, write to the Free Software\r * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r */\rpackage fr.gouv.finances.cp.utils.xml.marshal;\r\rimport fr.gouv.finances.cp.utils.xml.marshal.escapers.NamespaceContextImpl;\rimport java.io.IOException;\rimport java.io.OutputStreamWriter;\rimport java.nio.charset.Charset;\rimport java.text.SimpleDateFormat;\rimport java.util.Date;\rimport java.util.Iterator;\rimport java.util.Stack;\rimport java.util.Vector;\rimport javax.xml.namespace.QName;\rimport org.apache.log4j.Logger;\r\r/**\r * This class defines an xml writer.\r * <p>License : LGPL\r * @author: Christophe MARCHAND\r */\rpublic class XmlOutputter {\r private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");\r private static final SimpleDateFormat dt_sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZ");\r\r private static final Logger logger = Logger.getLogger(XmlOutputter.class);\r private static final String DEFAULT_ENCODING = "UTF-8";\r private String encoding;\r private OutputStreamWriter os;\r private static final String CRLF = System.getProperty("line.separator");\r private boolean writeStarted = false;\r private NamespaceContextImpl nsCtx;\r Charset cs = null;\r /**\r * Indent level. Incremented by <code>startTag(String)</code>, decremented by\r * <code>endTag(String)</code>.\r */\r private int indentLevel = 0;\r /**\r * Indent string.\r */\r public static final transient String INDENT_STR = " ";\r /**\r * A vector to store attributes.\r */\r private Vector<Attribute> attributes = null;\r /**\r * to store if attributes have been written or not.\r */\r private boolean attributesFlushed = false;\r /**\r * Indent string.\r */\r private String indentStr = INDENT_STR;\r /**\r * a stack to remember if top-element as child or not.\r */\r private Stack<MutableBoolean> stack = null;\r private CharacterEscaper escaper = null;\r private Stack<String> nsStack = null;\r\r class Attribute extends java.lang.Object {\r\r private String attName = null;\r private String value = null;\r private QName attQ = null;\r\r public Attribute(String attName, String value) {\r this.attName = attName;\r this.value = value;\r }\r\r public Attribute(QName attQ, String value) {\r this.attQ = attQ;\r this.value = value;\r }\r\r @Override\r public String toString() {\r StringBuffer sb = new StringBuffer();\r if (attName != null) {\r sb.append(" ").append(attName).append("=\"");\r } else {\r sb.append(" ");\r if (attQ.getPrefix() != null && attQ.getPrefix().length() > 0) {\r sb.append(attQ.getPrefix()).append(":");\r }\r sb.append(attQ.getLocalPart()).append("=\"");\r }\r if (value != null) {\r sb.append(value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll("'", "'"));\r }\r sb.append("\"");\r return sb.toString();\r }\r\r public String toString(CharacterEscaper escaper) {\r StringBuffer sb = new StringBuffer();\r if (attName != null) {\r sb.append(" ").append(attName).append("=\"");\r } else {\r sb.append(" ");\r if (attQ.getPrefix() != null && attQ.getPrefix().length() > 0) {\r sb.append(attQ.getPrefix()).append(":");\r }\r sb.append(attQ.getLocalPart()).append("=\"");\r }\r if (value != null) {\r sb.append(escaper.escapeString(value));\r }\r sb.append("\"");\r return sb.toString();\r }\r }\r\r /**\r * Constructs a XmlOutputter object based on a <code>OutputStream</code>.\r * \r * @param out the outputstream to write to\r * @param encoding The encoding of xml output\r * @see java.io.OutputStream\r */\r public XmlOutputter(OutputStreamWriter out, String encoding) {\r super();\r this.os = out;\r this.encoding = encoding;\r init();\r }\r\r /**\r * Constructs a XmlOutputter object based on a <code>OutputStream</code>, with the default encoding (UTF-8).\r * @param out the outputstream to write to\r */\r public XmlOutputter(OutputStreamWriter out) {\r this(out, DEFAULT_ENCODING);\r }\r\r /**\r * Writes a int attribute.\r * @param tag java.lang.String\r * @param value int\r */\r public void addAttribute(String attr, int value) {\r addAttribute(attr, Integer.toString(value));\r }\r\r /**\r * Writes a int attribute.\r * @param tag\r * @param value int\r */\r public void addAttribute(QName attr, int value) {\r addAttribute(attr, Integer.toString(value));\r }\r\r /**\r * Writes a long attribute.\r * @param tag java.lang.String\r * @param value long\r */\r public void addAttribute(String attr, long value) {\r addAttribute(attr, Long.toString(value));\r }\r\r /**\r * Writes a long attribute.\r * @param tag\r * @param value long\r */\r public void addAttribute(QName attr, long value) {\r addAttribute(attr, Long.toString(value));\r }\r\r /**\r * Writes an attribute.\r * @param tag java.lang.String\r * @param value java.lang.String\r */\r public void addAttribute(String attr, String value) {\r attributes.add(new Attribute(attr, value));\r }\r\r /**\r * Writes an attribute.\r * @param tag\r * @param value java.lang.String\r */\r public void addAttribute(QName attr, String value) {\r attributes.add(new Attribute(attr, value));\r }\r\r /**\r * Writes a BigDecimal attribute.\r * @param tag java.lang.String\r * @param value java.math.BigDecimal\r */\r public void addAttribute(String attr, java.math.BigDecimal value) {\r addAttribute(attr, value.toString());\r }\r\r /**\r * Writes a BigDecimal attribute.\r * @param tag\r * @param value java.math.BigDecimal\r */\r public void addAttribute(QName attr, java.math.BigDecimal value) {\r addAttribute(attr, value.toString());\r }\r\r /**\r * Writes a boolean attribute.\r * @param tag java.lang.String\r * @param value boolean\r */\r public void addAttribute(String attr, boolean value) {\r addAttribute(attr, value ? "true" : "false");\r }\r\r /**\r * Writes a boolean attribute.\r * @param tag\r * @param value boolean\r */\r public void addAttribute(QName attr, boolean value) {\r addAttribute(attr, value ? "true" : "false");\r }\r /**\r * Writes a java.util.Date attribute, conforming to <tt>xs:date</tt>\r * @param attName\r * @param date\r */\r public void addAttribute(String attName, Date date) {\r addAttribute(attName,sdf.format(date));\r }\r /**\r * Writes a java.util.Date attribute, conforming to <tt>xs:date</tt>\r * @param attr\r * @param date\r */\r public void addAttribute(QName attr, Date date) {\r addAttribute(attr,sdf.format(date));\r }\r /**\r * Writes a java.util.Date attribute, conforming to <tt>xs:date</tt>\r * @param attName\r * @param date\r */\r public void addDateTimeAttribute(String attName, Date date) {\r addAttribute(attName,dt_sdf.format(date));\r }\r /**\r * Writes a java.util.Date attribute, conforming to <tt>xs:date</tt>\r * @param attr\r * @param date\r */\r public void addDateTimeAttribute(QName attr, Date date) {\r addAttribute(attr,dt_sdf.format(date));\r }\r\r /**\r * Adds character data (#CDATA) to encapsulated Writer.\r * @param cData java.lang.String\r */\r public void addCharacterData(String cData) {\r flushAttributes(false);\r try {\r os.write(escaper.escapeString(cData));\r } catch (Throwable t) {\r }\r if (cData.indexOf("\n") != (-1)) {\r (stack.peek()).setValue(true);\r }\r }\r\r public void addComment(String comment) {\r writeStarted = true;\r flushAttributes(false);\r try {\r os.write("<!-- ");\r os.write(comment);\r os.write(" -->");\r } catch (Throwable t) {\r }\r }\r\r /**\r * Close the stack-on-top element. If <code>tag</code> is different of stack-on-top,\r * throws an <code>InvalidParameterException</code>.\r * @param tag java.lang.String\r * @exception java.security.InvalidParameterException If tag name\r * doesn't match the previously opened one.\r */\r public void endTag(String tag) throws java.security.InvalidParameterException {\r if (attributesFlushed) {\r indentLevel--;\r MutableBoolean bool = (MutableBoolean) stack.pop();\r if (bool.booleanValue()) {\r try {\r writeIndent();\r } catch (Throwable t) {\r }\r }\r try {\r os.write("</");\r os.write(tag);\r os.write(">");\r } catch (Throwable t) {\r }\r if (indentLevel == 0) {\r try {\r os.write(CRLF);\r } catch (Throwable t) {\r }\r }\r } else {\r flushAttributes(true);\r indentLevel--;\r }\r }\r\r public void endTag(QName tag) throws java.security.InvalidParameterException {\r if (attributesFlushed) {\r indentLevel--;\r MutableBoolean bool = (MutableBoolean) stack.pop();\r if (bool.booleanValue()) {\r try {\r writeIndent();\r } catch (Throwable t) {\r }\r }\r try {\r os.write("</");\r if (tag.getPrefix() != null && tag.getPrefix().length() > 0) {\r os.write(tag.getPrefix());\r os.write(":");\r }\r os.write(tag.getLocalPart());\r os.write(">");\r } catch (Throwable t) {\r }\r\r if (indentLevel == 0) {\r try {\r os.write(CRLF);\r } catch (Throwable t) {\r }\r }\r\r } else {\r flushAttributes(true);\r indentLevel--;\r }\r String ns = tag.getPrefix().concat(":").concat(tag.getNamespaceURI());\r String pushed = nsStack.pop();\r if (ns.equals(pushed)) {\r nsCtx.removeMapping(tag.getPrefix());\r }\r }\r\r /**\r * writes attributes to writer. Adds <code>/></code> if <code>close</code>,\r * and just <code>></code> otherwise.\r * @param close boolean\r */\r private void flushAttributes(boolean close) {\r if (!attributesFlushed) {\r for (Attribute attr : attributes) {\r try {\r os.write(attr.toString(escaper));\r } catch (Throwable t) {\r }\r }\r attributesFlushed = true;\r try {\r if (close) {\r os.write("/>");\r } else {\r os.write(">");\r }\r } catch (Throwable t) {\r }\r }\r }\r\r public void addCData(String cData) {\r flushAttributes(false);\r try{\r os.write("<![CDATA[");\r os.write(cData);\r os.write("]]>");\r } catch(IOException ex) {\r // TODO, maybe\r }\r }\r\r /**\r * Class initialization method. Called by all constructors.\r * If you override this method, do not forget to add <code>super.init()</code>\r * in your code.\r */\r private void init() throws RuntimeException {\r String osEncoding = fmtEncoding(os.getEncoding());\r if(!osEncoding.equals(fmtEncoding(encoding))) {\r logger.debug("compare "+osEncoding+" to "+fmtEncoding(encoding));\r throw new RuntimeException("Can not create an " + encoding + "-XmlOutputter on a " + os.getEncoding() + "-OutputStreamWritter");\r }\r attributes = new Vector<Attribute>();\r stack = new Stack<MutableBoolean>();\r writeStarted = true;\r escaper = CharacterEscaperFactory.getCharacterEscaper(encoding);\r nsCtx = new NamespaceContextImpl();\r nsStack = new Stack<String>();\r try {\r os.write("<?xml version=\"1.0\" encoding=\"");\r os.write(encoding);\r os.write("\"?");\r } catch (Throwable t) {\r }\r }\r\r private static String fmtEncoding(String encoding) {\r StringBuilder sb = new StringBuilder();\r for(char c:encoding.toCharArray()) {\r if('A'<=c && c<='Z') sb.append(c);\r if('0'<=c && c<='9') sb.append(c);\r if('a'<=c && c<='z') sb.append(Character.toUpperCase(c));\r }\r return sb.toString();\r }\r\r /**\r * An easy way to define an custom indent string.\r * @param s java.lang.String\r */\r public void setIndentStr(String s) {\r indentStr = s;\r }\r\r /**\r * Opens a new Tag.\r * @param tag java.lang.String\r */\r public void startTag(String tag) {\r flushAttributes(false);\r attributesFlushed = false;\r attributes.removeAllElements();\r try {\r writeIndent();\r os.write("<");\r os.write(tag);\r indentLevel++;\r if (!stack.isEmpty()) {\r ((MutableBoolean) stack.peek()).setValue(true);\r }\r } catch (Throwable t) {\r }\r stack.push(new MutableBoolean(false));\r }\r\r public void startTag(QName tag) {\r flushAttributes(false);\r attributesFlushed = false;\r attributes.removeAllElements();\r try {\r writeIndent();\r os.write("<");\r if (tag.getPrefix() != null && tag.getPrefix().length() > 0) {\r os.write(tag.getPrefix());\r os.write(":");\r }\r os.write(tag.getLocalPart());\r Iterator it = nsCtx.getPrefixes(tag.getNamespaceURI());\r if (it == null) {\r os.write(" xmlns");\r if (tag.getPrefix() != null && tag.getPrefix().length() > 0) {\r os.write(":");\r os.write(tag.getPrefix());\r }\r os.write("=\"");\r os.write(tag.getNamespaceURI());\r os.write("\"");\r nsCtx.addMapping(tag.getPrefix(), tag.getNamespaceURI());\r nsStack.push(tag.getPrefix().concat(":").concat(tag.getNamespaceURI()));\r } else {\r nsStack.push(null);\r }\r indentLevel++;\r if (!stack.isEmpty()) {\r ((MutableBoolean) stack.peek()).setValue(true);\r }\r } catch (Throwable t) {\r }\r stack.push(new MutableBoolean(false));\r }\r\r /**\r * Writes the needed indentation.\r */\r public void writeIndent() throws IOException {\r os.write(CRLF);\r for (int i = 0; i < indentLevel; i++) {\r os.write(indentStr);\r }\r }\r\r public void close() throws IOException {\r os.flush();\r os.close();\r }\r\r public OutputStreamWriter getWriter() {\r return os;\r }\r}\r\r
\ No newline at end of file
+/*\r * Copyright \r * 2005 axYus - www.axyus.com\r * 2005 C.Marchand - christophe.marchand@axyus.com\r * \r * This file is part of XEMELIOS.\r * \r * XEMELIOS is free software; you can redistribute it and/or modify\r * it under the terms of the GNU Lesser General Public License as published by\r * the Free Software Foundation; either version 2 of the License, or\r * (at your option) any later version.\r * \r * XEMELIOS is distributed in the hope that it will be useful,\r * but WITHOUT ANY WARRANTY; without even the implied warranty of\r * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r * GNU Lesser General Public License for more details.\r * \r * You should have received a copy of the GNU Lesser General Public License\r * along with XEMELIOS; if not, write to the Free Software\r * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r */\rpackage fr.gouv.finances.cp.utils.xml.marshal;\r\rimport fr.gouv.finances.cp.utils.xml.marshal.escapers.NamespaceContextImpl;\rimport java.io.IOException;\rimport java.io.OutputStreamWriter;\rimport java.nio.charset.Charset;\rimport java.text.SimpleDateFormat;\rimport java.util.Date;\rimport java.util.Iterator;\rimport java.util.Stack;\rimport java.util.Vector;\rimport javax.xml.namespace.QName;\rimport org.apache.log4j.Logger;\r\r/**\r * This class defines an xml writer.\r * <p>License : LGPL\r * @author: Christophe MARCHAND\r */\rpublic class XmlOutputter {\r private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");\r private static final SimpleDateFormat dt_sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZ");\r\r private static final Logger logger = Logger.getLogger(XmlOutputter.class);\r private static final String DEFAULT_ENCODING = "UTF-8";\r private String encoding;\r private OutputStreamWriter os;\r private static final String CRLF = System.getProperty("line.separator");\r private boolean writeStarted = false;\r private NamespaceContextImpl nsCtx;\r Charset cs = null;\r /**\r * Indent level. Incremented by <code>startTag(String)</code>, decremented by\r * <code>endTag(String)</code>.\r */\r private int indentLevel = 0;\r /**\r * Indent string.\r */\r public static final transient String INDENT_STR = " ";\r /**\r * A vector to store attributes.\r */\r private Vector<Attribute> attributes = null;\r /**\r * to store if attributes have been written or not.\r */\r private boolean attributesFlushed = false;\r /**\r * Indent string.\r */\r private String indentStr = INDENT_STR;\r /**\r * a stack to remember if top-element as child or not.\r */\r private Stack<MutableBoolean> stack = null;\r private CharacterEscaper escaper = null;\r private Stack<String> nsStack = null;\r\r class Attribute extends java.lang.Object {\r\r private String attName = null;\r private String value = null;\r private QName attQ = null;\r\r public Attribute(String attName, String value) {\r this.attName = attName;\r this.value = value;\r }\r\r public Attribute(QName attQ, String value) {\r this.attQ = attQ;\r this.value = value;\r }\r\r @Override\r public String toString() {\r StringBuffer sb = new StringBuffer();\r if (attName != null) {\r sb.append(" ").append(attName).append("=\"");\r } else {\r sb.append(" ");\r if (attQ.getPrefix() != null && attQ.getPrefix().length() > 0) {\r sb.append(attQ.getPrefix()).append(":");\r }\r sb.append(attQ.getLocalPart()).append("=\"");\r }\r if (value != null) {\r sb.append(value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll("'", "'"));\r }\r sb.append("\"");\r return sb.toString();\r }\r\r public String toString(CharacterEscaper escaper) {\r StringBuffer sb = new StringBuffer();\r if (attName != null) {\r sb.append(" ").append(attName).append("=\"");\r } else {\r sb.append(" ");\r if (attQ.getPrefix() != null && attQ.getPrefix().length() > 0) {\r sb.append(attQ.getPrefix()).append(":");\r }\r sb.append(attQ.getLocalPart()).append("=\"");\r }\r if (value != null) {\r sb.append(escaper.escapeString(value));\r }\r sb.append("\"");\r return sb.toString();\r }\r }\r\r /**\r * Constructs a XmlOutputter object based on a <code>OutputStream</code>.\r * \r * @param out the outputstream to write to\r * @param encoding The encoding of xml output\r * @see java.io.OutputStream\r */\r public XmlOutputter(OutputStreamWriter out, String encoding) {\r super();\r this.os = out;\r this.encoding = encoding;\r init();\r }\r\r /**\r * Constructs a XmlOutputter object based on a <code>OutputStream</code>, with the default encoding (UTF-8).\r * @param out the outputstream to write to\r */\r public XmlOutputter(OutputStreamWriter out) {\r this(out, DEFAULT_ENCODING);\r }\r\r /**\r * Writes a int attribute.\r * @param tag java.lang.String\r * @param value int\r */\r public void addAttribute(String attr, int value) {\r addAttribute(attr, Integer.toString(value));\r }\r\r /**\r * Writes a int attribute.\r * @param tag\r * @param value int\r */\r public void addAttribute(QName attr, int value) {\r addAttribute(attr, Integer.toString(value));\r }\r\r /**\r * Writes a long attribute.\r * @param tag java.lang.String\r * @param value long\r */\r public void addAttribute(String attr, long value) {\r addAttribute(attr, Long.toString(value));\r }\r\r /**\r * Writes a long attribute.\r * @param tag\r * @param value long\r */\r public void addAttribute(QName attr, long value) {\r addAttribute(attr, Long.toString(value));\r }\r\r /**\r * Writes an attribute.\r * @param tag java.lang.String\r * @param value java.lang.String\r */\r public void addAttribute(String attr, String value) {\r attributes.add(new Attribute(attr, value));\r }\r\r /**\r * Writes an attribute.\r * @param tag\r * @param value java.lang.String\r */\r public void addAttribute(QName attr, String value) {\r attributes.add(new Attribute(attr, value));\r }\r\r /**\r * Writes a BigDecimal attribute.\r * @param tag java.lang.String\r * @param value java.math.BigDecimal\r */\r public void addAttribute(String attr, java.math.BigDecimal value) {\r addAttribute(attr, value.toString());\r }\r\r /**\r * Writes a BigDecimal attribute.\r * @param tag\r * @param value java.math.BigDecimal\r */\r public void addAttribute(QName attr, java.math.BigDecimal value) {\r addAttribute(attr, value.toString());\r }\r\r /**\r * Writes a boolean attribute.\r * @param tag java.lang.String\r * @param value boolean\r */\r public void addAttribute(String attr, boolean value) {\r addAttribute(attr, value ? "true" : "false");\r }\r\r /**\r * Writes a boolean attribute.\r * @param tag\r * @param value boolean\r */\r public void addAttribute(QName attr, boolean value) {\r addAttribute(attr, value ? "true" : "false");\r }\r /**\r * Writes a java.util.Date attribute, conforming to <tt>xs:date</tt>\r * @param attName\r * @param date\r */\r public void addAttribute(String attName, Date date) {\r addAttribute(attName,sdf.format(date));\r }\r /**\r * Writes a java.util.Date attribute, conforming to <tt>xs:date</tt>\r * @param attr\r * @param date\r */\r public void addAttribute(QName attr, Date date) {\r addAttribute(attr,sdf.format(date));\r }\r /**\r * Writes a java.util.Date attribute, conforming to <tt>xs:date</tt>\r * @param attName\r * @param date\r */\r public void addDateTimeAttribute(String attName, Date date) {\r addAttribute(attName,dt_sdf.format(date));\r }\r /**\r * Writes a java.util.Date attribute, conforming to <tt>xs:date</tt>\r * @param attr\r * @param date\r */\r public void addDateTimeAttribute(QName attr, Date date) {\r addAttribute(attr,dt_sdf.format(date));\r }\r\r /**\r * Adds character data (#CDATA) to encapsulated Writer.\r * @param cData java.lang.String\r */\r public void addCharacterData(String cData) {\r flushAttributes(false);\r try {\r os.write(escaper.escapeString(cData));\r } catch (Throwable t) {\r }\r if (cData.indexOf("\n") != (-1)) {\r (stack.peek()).setValue(true);\r }\r }\r\r public void addComment(String comment) {\r writeStarted = true;\r flushAttributes(false);\r try {\r os.write("<!-- ");\r os.write(comment);\r os.write(" -->");\r } catch (Throwable t) {\r }\r }\r\r /**\r * Close the stack-on-top element. If <code>tag</code> is different of stack-on-top,\r * throws an <code>InvalidParameterException</code>.\r * @param tag java.lang.String\r * @exception java.security.InvalidParameterException If tag name\r * doesn't match the previously opened one.\r */\r public void endTag(String tag) throws java.security.InvalidParameterException {\r if (attributesFlushed) {\r indentLevel--;\r MutableBoolean bool = (MutableBoolean) stack.pop();\r if (bool.booleanValue()) {\r try {\r writeIndent();\r } catch (Throwable t) {\r }\r }\r try {\r os.write("</");\r os.write(tag);\r os.write(">");\r } catch (Throwable t) {\r }\r if (indentLevel == 0) {\r try {\r os.write(CRLF);\r } catch (Throwable t) {\r }\r }\r } else {\r flushAttributes(true);\r indentLevel--;\r }\r }\r\r public void endTag(QName tag) throws java.security.InvalidParameterException {\r if (attributesFlushed) {\r indentLevel--;\r MutableBoolean bool = (MutableBoolean) stack.pop();\r if (bool.booleanValue()) {\r try {\r writeIndent();\r } catch (Throwable t) {\r }\r }\r try {\r os.write("</");\r if (tag.getPrefix() != null && tag.getPrefix().length() > 0) {\r os.write(tag.getPrefix());\r os.write(":");\r }\r os.write(tag.getLocalPart());\r os.write(">");\r } catch (Throwable t) {\r }\r\r if (indentLevel == 0) {\r try {\r os.write(CRLF);\r } catch (Throwable t) {\r }\r }\r\r } else {\r flushAttributes(true);\r indentLevel--;\r }\r String ns = tag.getPrefix().concat(":").concat(tag.getNamespaceURI());\r String pushed = nsStack.pop();\r if (ns.equals(pushed)) {\r nsCtx.removeMapping(tag.getPrefix());\r }\r }\r\r /**\r * writes attributes to writer. Adds <code>/></code> if <code>close</code>,\r * and just <code>></code> otherwise.\r * @param close boolean\r */\r private void flushAttributes(boolean close) {\r if (!attributesFlushed) {\r for (Attribute attr : attributes) {\r try {\r os.write(attr.toString(escaper));\r } catch (Throwable t) {\r }\r }\r attributesFlushed = true;\r try {\r if (close) {\r os.write("/>");\r } else {\r os.write(">");\r }\r } catch (Throwable t) {\r }\r }\r }\r\r public void addCData(String cData) {\r flushAttributes(false);\r try{\r os.write("<![CDATA[");\r os.write(cData);\r os.write("]]>");\r } catch(IOException ex) {\r // TODO, maybe\r }\r }\r\r /**\r * Class initialization method. Called by all constructors.\r * If you override this method, do not forget to add <code>super.init()</code>\r * in your code.\r */\r private void init() throws RuntimeException {\r String osEncoding = fmtEncoding(os.getEncoding());\r if(!osEncoding.equals(fmtEncoding(encoding))) {\r logger.debug("compare "+osEncoding+" to "+fmtEncoding(encoding));\r throw new RuntimeException("Can not create an " + encoding + "-XmlOutputter on a " + os.getEncoding() + "-OutputStreamWritter");\r }\r attributes = new Vector<Attribute>();\r stack = new Stack<MutableBoolean>();\r writeStarted = true;\r escaper = CharacterEscaperFactory.getCharacterEscaper(encoding);\r nsCtx = new NamespaceContextImpl();\r nsStack = new Stack<String>();\r try {\r os.write("<?xml version=\"1.0\" encoding=\"");\r os.write(encoding);\r os.write("\"?");\r } catch (Throwable t) {\r }\r }\r\r private static String fmtEncoding(String encoding) {\r StringBuilder sb = new StringBuilder();\r for(char c:encoding.toCharArray()) {\r if('A'<=c && c<='Z') sb.append(c);\r if('0'<=c && c<='9') sb.append(c);\r if('a'<=c && c<='z') sb.append(Character.toUpperCase(c));\r }\r return sb.toString();\r }\r\r /**\r * An easy way to define an custom indent string.\r * @param s java.lang.String\r */\r public void setIndentStr(String s) {\r indentStr = s;\r }\r\r /**\r * Opens a new Tag.\r * @param tag java.lang.String\r */\r public void startTag(String tag) {\r flushAttributes(false);\r attributesFlushed = false;\r attributes.removeAllElements();\r try {\r writeIndent();\r os.write("<");\r os.write(tag);\r indentLevel++;\r if (!stack.isEmpty()) {\r ((MutableBoolean) stack.peek()).setValue(true);\r }\r } catch (Throwable t) {\r }\r stack.push(new MutableBoolean(false));\r }\r\r public void startTag(QName tag) {\r flushAttributes(false);\r attributesFlushed = false;\r attributes.removeAllElements();\r try {\r writeIndent();\r os.write("<");\r if (tag.getPrefix() != null && tag.getPrefix().length() > 0) {\r os.write(tag.getPrefix());\r os.write(":");\r }\r os.write(tag.getLocalPart());\r Iterator it = nsCtx.getPrefixes(tag.getNamespaceURI());\r if (it == null) {\r os.write(" xmlns");\r if (tag.getPrefix() != null && tag.getPrefix().length() > 0) {\r os.write(":");\r os.write(tag.getPrefix());\r }\r os.write("=\"");\r os.write(tag.getNamespaceURI());\r os.write("\"");\r nsCtx.addMapping(tag.getPrefix(), tag.getNamespaceURI());\r nsStack.push(tag.getPrefix().concat(":").concat(tag.getNamespaceURI()));\r } else {\r nsStack.push(null);\r }\r indentLevel++;\r if (!stack.isEmpty()) {\r ((MutableBoolean) stack.peek()).setValue(true);\r }\r } catch (Throwable t) {\r }\r stack.push(new MutableBoolean(false));\r }\r\r /**\r * Writes the needed indentation.\r */\r public void writeIndent() throws IOException {\r os.write(CRLF);\r for (int i = 0; i < indentLevel; i++) {\r os.write(indentStr);\r }\r }\r\r public void close() throws IOException {\r os.flush();\r os.close();\r }\r\r public OutputStreamWriter getWriter() {\r return os;\r }\r}\r\r
\ No newline at end of file