1 24 package org.riotfamily.common.markup; 25 26 import java.io.PrintWriter ; 27 28 import org.riotfamily.common.util.FormatUtils; 29 30 49 public class TagWriter { 50 51 private static final int STATE_CLOSED = 0; 52 53 private static final int STATE_START = 1; 54 55 private static final int STATE_BODY = 2; 56 57 private static final int STATE_CDATA = 3; 58 59 private boolean empty = false; 60 61 private String tagName; 62 63 private PrintWriter writer; 64 65 private boolean xhtml = true; 66 67 private int state = STATE_CLOSED; 68 69 private TagWriter parent; 70 71 public TagWriter(PrintWriter writer) { 72 this.writer = writer; 73 } 74 75 private TagWriter(TagWriter parent) { 76 this.parent = parent; 77 this.writer = parent.writer; 78 this.xhtml = parent.xhtml; 79 } 80 81 public void setXhtml(boolean xhtml) { 82 this.xhtml = xhtml; 83 } 84 85 public TagWriter start(String tagName) { 86 return start(tagName, false); 87 } 88 89 public TagWriter startEmpty(String tagName) { 90 return start(tagName, true); 91 } 92 93 public TagWriter start(String tagName, boolean empty) { 94 if (state != STATE_CLOSED) { 95 if (state == STATE_START) { 96 body(); 97 } 98 return new TagWriter(this).start(tagName, empty); 99 } 100 else { 101 this.tagName = tagName; 102 this.empty = empty; 103 writer.write('<'); 104 writer.write(tagName); 105 state = STATE_START; 106 return this; 107 } 108 } 109 110 public TagWriter attribute(String name) { 111 String value = null; 112 if (xhtml) { 113 value = name; 114 } 115 return attribute(name, value, true); 116 } 117 118 public TagWriter attribute(String name, int value) { 119 if (state != STATE_START) { 120 throw new IllegalStateException ("start() must be called first"); 121 } 122 writer.write(' '); 123 writer.write(name); 124 writer.write('='); 125 writer.write('"'); 126 writer.write(String.valueOf(value)); 127 writer.write('"'); 128 return this; 129 } 130 131 public TagWriter attribute(String name, boolean present) { 132 String value = present ? name : null; 133 return attribute(name, value, false); 134 } 135 136 public TagWriter attribute(String name, String value) { 137 return attribute(name, value, false); 138 } 139 140 public TagWriter attribute(String name, String value, boolean renderEmpty) { 141 if (state != STATE_START) { 142 throw new IllegalStateException ("start() must be called first"); 143 } 144 if (value == null && !renderEmpty) { 145 return this; 146 } 147 writer.write(' '); 148 writer.write(name); 149 if (value != null) { 150 writer.write('='); 151 writer.write('"'); 152 writer.write(FormatUtils.xmlEscape(value)); 153 writer.write('"'); 154 } 155 return this; 156 } 157 158 public TagWriter body() { 159 if (state != STATE_START) { 160 throw new IllegalStateException ("start() must be called first"); 161 } 162 if (empty) { 163 throw new IllegalStateException ("Body not allowed for empty tags"); 164 } 165 writer.write('>'); 166 state = STATE_BODY; 167 return this; 168 } 169 170 public TagWriter body(String body) { 171 return body(body, true); 172 } 173 174 public TagWriter body(String body, boolean escapeHtml) { 175 body(); 176 if (body != null) { 177 if (escapeHtml) { 178 writer.write(FormatUtils.xmlEscape(body)); 179 } 180 else { 181 writer.write(body); 182 } 183 } 184 return this; 185 } 186 187 public TagWriter cData() { 188 if (state != STATE_BODY) { 189 throw new IllegalStateException ("body() must be called first"); 190 } 191 if (state == STATE_CDATA) { 192 throw new IllegalStateException ( 193 "cData() must not be called within a CDATA section"); 194 } 195 writer.write("<![CDATA[\n"); 196 state = STATE_CDATA; 197 return this; 198 } 199 200 public TagWriter closeCData() { 201 if (state != STATE_CDATA) { 202 throw new IllegalStateException ("cData() must be called first"); 203 } 204 writer.write("]]>"); 205 state = STATE_BODY; 206 return this; 207 } 208 209 public TagWriter print(String s) { 210 if (state < STATE_BODY) { 211 throw new IllegalStateException ("body() must be called first"); 212 } 213 writer.print(state == STATE_CDATA ? s : FormatUtils.xmlEscape(s)); 214 return this; 215 } 216 217 public TagWriter println(String s) { 218 print(s); 219 writer.println(); 220 return this; 221 } 222 223 public TagWriter println() { 224 writer.println(); 225 return this; 226 } 227 228 public TagWriter end() { 229 if (state == STATE_CLOSED) { 230 throw new IllegalStateException ("Tag already closed"); 231 } 232 if (empty) { 233 if (xhtml) { 234 writer.write('/'); 235 } 236 writer.write('>'); 237 } 238 else { 239 if (state == STATE_CDATA) { 240 closeCData(); 241 } 242 if (state < STATE_BODY) { 243 body(); 244 } 245 writer.write('<'); 246 writer.write('/'); 247 writer.write(tagName); 248 writer.write('>'); 249 } 250 state = STATE_CLOSED; 251 return parent != null ? parent : this; 252 } 253 254 public void closeAll() { 255 TagWriter writer = this; 256 while (writer != null) { 257 writer.end(); 258 writer = writer.parent; 259 } 260 } 261 262 } | Popular Tags |