1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.xml;
20
21 import java.io.Closeable;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.OutputStreamWriter;
25 import java.util.Map;
26 import java.util.Stack;
27
28 import org.eclipse.jetty.util.StringUtil;
29
30 public class XmlAppendable
31 {
32 private final String SPACES=" ";
33 private final Appendable _out;
34 private final int _indent;
35 private final Stack<String> _tags = new Stack<>();
36 private String _space="";
37
38 public XmlAppendable(OutputStream out,String encoding) throws IOException
39 {
40 this(new OutputStreamWriter(out,encoding),encoding);
41 }
42
43 public XmlAppendable(Appendable out) throws IOException
44 {
45 this(out,2);
46 }
47
48 public XmlAppendable(Appendable out,String encoding) throws IOException
49 {
50 this(out,2,encoding);
51 }
52
53 public XmlAppendable(Appendable out, int indent) throws IOException
54 {
55 this(out,indent,"utf-8");
56 }
57
58 public XmlAppendable(Appendable out, int indent, String encoding) throws IOException
59 {
60 _out=out;
61 _indent=indent;
62 _out.append("<?xml version=\"1.0\" encoding=\""+encoding+"\"?>\n");
63 }
64
65 public XmlAppendable openTag(String tag, Map<String,String> attributes) throws IOException
66 {
67 _out.append(_space).append('<').append(tag);
68 attributes(attributes);
69
70 _out.append(">\n");
71 _space=_space+SPACES.substring(0,_indent);
72 _tags.push(tag);
73 return this;
74 }
75
76 public XmlAppendable openTag(String tag) throws IOException
77 {
78 _out.append(_space).append('<').append(tag).append(">\n");
79 _space=_space+SPACES.substring(0,_indent);
80 _tags.push(tag);
81 return this;
82 }
83
84 public XmlAppendable content(String s) throws IOException
85 {
86 if (s!=null)
87 _out.append(StringUtil.sanitizeXmlString(s));
88
89 return this;
90 }
91
92 public XmlAppendable cdata(String s) throws IOException
93 {
94 _out.append("<![CDATA[").append(s).append("]]>");
95 return this;
96 }
97
98 public XmlAppendable tag(String tag) throws IOException
99 {
100 _out.append(_space).append('<').append(tag).append("/>\n");
101 return this;
102 }
103
104 public XmlAppendable tag(String tag, Map<String,String> attributes) throws IOException
105 {
106 _out.append(_space).append('<').append(tag);
107 attributes(attributes);
108 _out.append("/>\n");
109 return this;
110 }
111
112 public XmlAppendable tag(String tag,String content) throws IOException
113 {
114 _out.append(_space).append('<').append(tag).append('>');
115 content(content);
116 _out.append("</").append(tag).append(">\n");
117 return this;
118 }
119
120 public XmlAppendable tagCDATA(String tag,String data) throws IOException
121 {
122 _out.append(_space).append('<').append(tag).append('>');
123 cdata(data);
124 _out.append("</").append(tag).append(">\n");
125 return this;
126 }
127
128 public XmlAppendable tag(String tag, Map<String,String> attributes,String content) throws IOException
129 {
130 _out.append(_space).append('<').append(tag);
131 attributes(attributes);
132 _out.append('>');
133 content(content);
134 _out.append("</").append(tag).append(">\n");
135 return this;
136 }
137
138 public XmlAppendable closeTag() throws IOException
139 {
140 if (_tags.isEmpty())
141 throw new IllegalStateException("Tags closed");
142 String tag=_tags.pop();
143 _space=_space.substring(0,_space.length()-_indent);
144 _out.append(_space).append("</").append(tag).append(">\n");
145 if (_tags.isEmpty() && _out instanceof Closeable)
146 ((Closeable)_out).close();
147 return this;
148 }
149
150 private void attributes(Map<String,String> attributes) throws IOException
151 {
152 for (String k:attributes.keySet())
153 {
154 String v = attributes.get(k);
155 _out.append(' ').append(k).append("=\"");
156 content(v);
157 _out.append('"');
158 }
159 }
160
161 public void literal(String xml) throws IOException
162 {
163 _out.append(xml);
164 }
165
166 }