| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.xml; |
| |
| import java.io.Closeable; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.io.OutputStreamWriter; |
| import java.util.Map; |
| import java.util.Stack; |
| |
| import org.eclipse.jetty.util.StringUtil; |
| |
| public class XmlAppendable |
| { |
| private final String SPACES=" "; |
| private final Appendable _out; |
| private final int _indent; |
| private final Stack<String> _tags = new Stack<>(); |
| private String _space=""; |
| |
| public XmlAppendable(OutputStream out,String encoding) throws IOException |
| { |
| this(new OutputStreamWriter(out,encoding),encoding); |
| } |
| |
| public XmlAppendable(Appendable out) throws IOException |
| { |
| this(out,2); |
| } |
| |
| public XmlAppendable(Appendable out,String encoding) throws IOException |
| { |
| this(out,2,encoding); |
| } |
| |
| public XmlAppendable(Appendable out, int indent) throws IOException |
| { |
| this(out,indent,"utf-8"); |
| } |
| |
| public XmlAppendable(Appendable out, int indent, String encoding) throws IOException |
| { |
| _out=out; |
| _indent=indent; |
| _out.append("<?xml version=\"1.0\" encoding=\""+encoding+"\"?>\n"); |
| } |
| |
| public XmlAppendable openTag(String tag, Map<String,String> attributes) throws IOException |
| { |
| _out.append(_space).append('<').append(tag); |
| attributes(attributes); |
| |
| _out.append(">\n"); |
| _space=_space+SPACES.substring(0,_indent); |
| _tags.push(tag); |
| return this; |
| } |
| |
| public XmlAppendable openTag(String tag) throws IOException |
| { |
| _out.append(_space).append('<').append(tag).append(">\n"); |
| _space=_space+SPACES.substring(0,_indent); |
| _tags.push(tag); |
| return this; |
| } |
| |
| public XmlAppendable content(String s) throws IOException |
| { |
| if (s!=null) |
| _out.append(StringUtil.sanitizeXmlString(s)); |
| |
| return this; |
| } |
| |
| public XmlAppendable cdata(String s) throws IOException |
| { |
| _out.append("<![CDATA[").append(s).append("]]>"); |
| return this; |
| } |
| |
| public XmlAppendable tag(String tag) throws IOException |
| { |
| _out.append(_space).append('<').append(tag).append("/>\n"); |
| return this; |
| } |
| |
| public XmlAppendable tag(String tag, Map<String,String> attributes) throws IOException |
| { |
| _out.append(_space).append('<').append(tag); |
| attributes(attributes); |
| _out.append("/>\n"); |
| return this; |
| } |
| |
| public XmlAppendable tag(String tag,String content) throws IOException |
| { |
| _out.append(_space).append('<').append(tag).append('>'); |
| content(content); |
| _out.append("</").append(tag).append(">\n"); |
| return this; |
| } |
| |
| public XmlAppendable tagCDATA(String tag,String data) throws IOException |
| { |
| _out.append(_space).append('<').append(tag).append('>'); |
| cdata(data); |
| _out.append("</").append(tag).append(">\n"); |
| return this; |
| } |
| |
| public XmlAppendable tag(String tag, Map<String,String> attributes,String content) throws IOException |
| { |
| _out.append(_space).append('<').append(tag); |
| attributes(attributes); |
| _out.append('>'); |
| content(content); |
| _out.append("</").append(tag).append(">\n"); |
| return this; |
| } |
| |
| public XmlAppendable closeTag() throws IOException |
| { |
| if (_tags.isEmpty()) |
| throw new IllegalStateException("Tags closed"); |
| String tag=_tags.pop(); |
| _space=_space.substring(0,_space.length()-_indent); |
| _out.append(_space).append("</").append(tag).append(">\n"); |
| if (_tags.isEmpty() && _out instanceof Closeable) |
| ((Closeable)_out).close(); |
| return this; |
| } |
| |
| private void attributes(Map<String,String> attributes) throws IOException |
| { |
| for (String k:attributes.keySet()) |
| { |
| String v = attributes.get(k); |
| _out.append(' ').append(k).append("=\""); |
| content(v); |
| _out.append('"'); |
| } |
| } |
| |
| public void literal(String xml) throws IOException |
| { |
| _out.append(xml); |
| } |
| |
| } |