001: /*
002: * Created on Jan 28, 2005
003: *
004: */
005: package net.sf.thingamablog.generator;
006:
007: import java.io.IOException;
008: import java.io.StringWriter;
009: import java.io.Writer;
010: import java.util.Enumeration;
011: import java.util.Hashtable;
012: import java.util.Iterator;
013: import java.util.List;
014: import java.util.Vector;
015:
016: public class TemplateProcessor {
017: private static final String LT = "<";
018: private static final String GT = ">";
019: private static final String END_LT = "</";
020: private static final String TAG_LT = LT + '$';
021: private static final String TAG_GT = '$' + GT;
022:
023: public String processTemplate(String tmpl, TemplateContainer root) {
024: List temps = parseContainers(tmpl, root);
025: for (Iterator it = temps.iterator(); it.hasNext();) {
026: String curTmp = it.next().toString();
027: StringWriter sw = new StringWriter(curTmp.length() * 2);
028:
029: try {
030: writeContainer(curTmp, root, sw);
031: } catch (IOException ioe) {
032: }
033:
034: StringBuffer buf = sw.getBuffer();
035: tmpl = replace(curTmp, buf.substring(0, buf.length()), tmpl);
036: }
037:
038: return tmpl;
039: }
040:
041: public void writeContainer(String tmpl, TemplateContainer cont,
042: Writer writer) throws IOException {
043: cont.initialize(parseAttributes(tmpl, cont));
044: if (cont.isVisible()) {
045: do {
046: String result = processVariables(stripOffTags(tmpl,
047: cont), cont);
048: if (cont.prefix() != null)
049: writer.write(cont.prefix());
050: writer.write(processContainers(result, cont));
051: if (cont.postfix() != null)
052: writer.write(cont.postfix());
053: } while (cont.processAgain());
054: }
055: }
056:
057: public List parseContainers(String tmpl, TemplateContainer tc) {
058: int _pos = 0;
059: Vector temps = new Vector();
060: String containerStart = LT + tc.getName();
061: String closeTag = END_LT + tc.getName() + GT;
062:
063: while (tmpl.indexOf(containerStart, _pos) > -1) {
064: int s = tmpl.indexOf(containerStart, _pos);//open tag begin
065: if (s < 0)//not found
066: continue;
067:
068: _pos = s + tc.getName().length() + 1; //update pos;
069:
070: char ch = tmpl.charAt(_pos);
071: if (ch != '>' && !Character.isWhitespace(ch))
072: continue; //this isn't the right tag,
073: //it only starts like the one we're looking for
074: //System.out.println("After tag = " + t.charAt(pos));
075:
076: //now we have to find the end ">" of the open tag
077: int otEnd = tmpl.indexOf(GT, _pos);
078: if (otEnd < 0)//incomplete tag
079: continue;
080:
081: _pos = otEnd;
082:
083: int e = tmpl.indexOf(closeTag, _pos);
084: if (e < 0)//incomple tag
085: continue;
086:
087: e += closeTag.length();
088: _pos = e;
089:
090: temps.add(tmpl.substring(s, e));
091: }
092:
093: return temps;
094: }
095:
096: private String stripOffTags(String t, TemplateContainer tc) {
097: int s = t.indexOf(GT); //end of open tag
098: int e = t.indexOf(END_LT + tc.getName() + GT);//end of close tag
099: if (s < 0 || e < 0 || (s + 1) >= t.length())
100: return t;
101: return t.substring(s + 1, e);
102: }
103:
104: private String processVariables(String tmpl, TemplateContainer tc) {
105: List list = tc.getTags();
106: if (list != null) {
107: Iterator it = list.iterator();
108: while (it.hasNext()) {
109: TemplateTag tag = (TemplateTag) it.next();
110: tmpl = parseVariable(tmpl, tag, tc.getValueForTag(tag));
111: }
112: }
113: return tmpl;
114: }
115:
116: private String processContainers(String tmpl, TemplateContainer tc) {
117: List list = tc.getContainers();
118: if (list != null) {
119: Iterator it = list.iterator();
120: while (it.hasNext()) {
121: tmpl = processTemplate(tmpl, (TemplateContainer) it
122: .next());
123: }
124: }
125: return tmpl;
126: }
127:
128: private String parseVariable(String tmpl, TemplateTag tag,
129: Object obj) {
130: int _pos = 0;
131: String attribsStart = TAG_LT;
132: String attribsEnd = TAG_GT;
133: String tagStart = attribsStart + tag.getName();
134:
135: while ((_pos = tmpl.indexOf(tagStart, _pos)) > -1) {
136: int end = tmpl.indexOf(attribsEnd, _pos)
137: + attribsEnd.length();
138: if (end < _pos)//no more
139: return tmpl;
140:
141: String var = tmpl.substring(_pos, end);
142: int nameLen = tag.getName().length();
143: int normalLen = attribsStart.length() + nameLen
144: + attribsEnd.length();
145:
146: if (var.length() > normalLen) {
147: //this tag should have whitespace between the tag name and
148: //attribute list because it's longer than
149: //the normal, no-attribute, length.
150: char c = var.charAt(attribsStart.length() + nameLen);
151: if (!Character.isWhitespace(c)) {
152: //System.out.println(c + " - " + tag.getName() + " - " + var);
153: //No whitespace found so
154: //this isn't the right tag, it only starts
155: //like the one we're looking for, so pass it over
156: _pos = end;
157: continue;
158: }
159: }
160:
161: Hashtable ht = parseAttributes(var, tag);
162: String val = tag.process(obj, ht);
163: tmpl = replace(var, val, tmpl);
164: }
165:
166: return tmpl;
167: }
168:
169: private Hashtable parseAttributes(String t, TemplateElement te) {
170: Hashtable defaults = te.getDefaultAttributes();
171: if (defaults == null)//don't allow null attributes
172: defaults = new Hashtable();//empty attributes
173: Hashtable ht = new Hashtable(defaults);//copy defaults
174:
175: String attribsStart = getAttribsStart(te) + te.getName();
176: String attribsEnd = getAttribsEnd(te);
177: int s = t.indexOf(attribsStart, 0);//open tag begin
178: if (s == -1)//not found
179: return ht;
180:
181: int e = t.indexOf(attribsEnd, s + attribsStart.length());
182: if (e == -1 || e == (s + attribsStart.length()))//no attributes given, use defaults
183: return ht;
184:
185: String attribs = t.substring(s + attribsStart.length(), e)
186: .trim();
187: //System.out.println(attribs);
188: attribs = " " + attribs;//ensure the first attrib has a prefixed space
189: char ws[] = { ' ', '\n', '\t' };
190:
191: for (Enumeration eEnum = ht.keys(); eEnum.hasMoreElements();) {
192: String key = eEnum.nextElement().toString();
193: int p = 0;
194: for (int i = 0; i < ws.length; i++) {
195: p = attribs.indexOf(ws[i] + key);
196: if (p != -1)
197: break;
198: }
199: if (p == -1)//attribute wasn't found, default will be used
200: continue;
201: //skip over the space and attribute name
202: p += key.length() + 1;
203:
204: try {
205: //iterate thru whitespace till we hit equals
206: while (Character.isWhitespace(attribs.charAt(p++)))
207: ;
208: if (attribs.charAt(--p) != '=')
209: break;
210: //iterate thru whitespace till we hit opening quote
211: while (Character.isWhitespace(attribs.charAt(++p)))
212: ;
213: if (attribs.charAt(p) != '\"')
214: break;
215:
216: int end = attribs.indexOf("\"", p + 1);//end quote
217: if (end == -1)
218: break;//no closing quote
219:
220: //FIXED with trim() this screws up attribs like glue=", "
221: //String val = attribs.substring(p, end).trim();
222: String val = attribs.substring(p, end);
223: //remove quotes
224: if (val.startsWith("\"") /*&& val.length() > 1*/)
225: val = val.substring(1, val.length());
226:
227: if (val.endsWith("\"") /*&& val.length() > 1*/)
228: val = val.substring(0, val.length() - 1);
229:
230: ht.put(key, val);
231: //System.out.println(key + " = " +val);
232:
233: } catch (IndexOutOfBoundsException ex) {
234: break;
235: }
236: }
237:
238: return ht;
239: }
240:
241: private String replace(String var, String val, String tmpl) {
242: if (var.equals("") || var == null)
243: return tmpl;
244: StringBuffer sb = new StringBuffer(val.length() + tmpl.length());
245: sb.append(tmpl);
246: while (sb.indexOf(var) != -1 && !var.equals(val)) {
247: int s = sb.indexOf(var);
248: int e = s + var.length();
249: sb.delete(s, e);
250: sb.insert(s, val);
251: }
252: return sb.substring(0, sb.length());
253: }
254:
255: private String getAttribsStart(TemplateElement te) {
256: if (te instanceof TemplateTag)
257: return TAG_LT;
258: return LT;
259: }
260:
261: private String getAttribsEnd(TemplateElement te) {
262: if (te instanceof TemplateTag)
263: return TAG_GT;
264: return GT;
265: }
266: }
|