1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sourceforge.jtpl;
17
18 import java.io.File;
19 import java.io.FileReader;
20 import java.io.IOException;
21 import java.io.Reader;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.Set;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public class Jtpl
52 {
53 private HashMap blocks = new HashMap();
54 private HashMap parsedBlocks = new HashMap();
55 private HashMap subBlocks = new HashMap();
56 private HashMap vars = new HashMap();
57
58 private boolean failSilently = false;
59 private boolean implicitMain = false;
60
61
62
63
64
65
66
67 public Jtpl(String fileName) throws IOException
68 {
69 this(new File(fileName));
70
71 this.failSilently = true;
72 }
73
74
75
76
77
78
79 public Jtpl(File file) throws IOException
80 {
81 FileReader fr = new FileReader(file);
82 String fileText = readFile(fr);
83 makeTree(fileText);
84 }
85
86
87
88
89
90
91 public Jtpl(Reader template) throws IOException
92 {
93 String fileText = readFile(template);
94 makeTree(fileText);
95 }
96
97
98
99
100
101
102
103
104 public void assign(String varName, String varData)
105 {
106 vars.put(varName, varData);
107 }
108
109
110
111
112 public String out()
113 {
114 if (this.implicitMain) {
115 this.parse("main");
116 }
117 Object main = parsedBlocks.get("main");
118 if (main == null) {
119 throw new IllegalStateException("'main' block not parsed");
120 }
121 return(main.toString());
122 }
123
124
125
126
127
128
129
130
131
132
133 public void parse(String blockName) throws IllegalArgumentException
134 {
135 String copy = "";
136 if (implicitMain && !"main".equals(blockName) && !blockName.startsWith("main.")) {
137 blockName = "main." + blockName;
138 }
139 try {
140 copy = blocks.get(blockName).toString();
141 } catch (NullPointerException e) {
142 if (!this.failSilently) throw new IllegalArgumentException(
143 "Block '" + blockName + "' not found." +
144 " Matches " + locateBlock(blockName));
145 }
146 Pattern pattern = Pattern.compile("\\{([\\w\\.]+)\\}");
147 Matcher matcher = pattern.matcher(copy);
148 pattern = Pattern.compile("_BLOCK_\\.(.+)");
149 for (Matcher matcher2; matcher.find();)
150 {
151 String match = matcher.group(1);
152 matcher2 = pattern.matcher(match);
153 if (matcher2.find())
154 {
155 if (parsedBlocks.containsKey(matcher2.group(1)))
156 {
157 copy = copy.replaceFirst("\\{"+match+"\\}", escape(
158 parsedBlocks.get(matcher2.group(1)).toString()));
159 }
160 else
161 {
162 copy = copy.replaceFirst("\\{"+match+"\\}", "");
163 }
164 }
165 else
166 {
167 if (vars.containsKey(match))
168 {
169 copy = copy.replaceFirst("\\{"+match+"\\}", escape(
170 vars.get(match).toString()));
171 }
172 else
173 {
174
175
176
177 }
178 }
179 }
180 if (parsedBlocks.containsKey(blockName))
181 {
182 parsedBlocks.put(blockName, parsedBlocks.get(blockName) + copy);
183 }
184 else
185 {
186 parsedBlocks.put(blockName, copy);
187 }
188 if (subBlocks.containsKey(blockName))
189 {
190 parsedBlocks.put(subBlocks.get(blockName), "");
191 }
192 }
193
194
195
196
197
198
199
200 protected String escape(String replacement) {
201 return replacement.replace("\\", "\\\\").replace("$", "\\$");
202 }
203
204
205
206
207
208
209
210 protected Set locateBlock(final String blockName) {
211 Set matches = new java.util.HashSet();
212 for (Iterator it = blocks.keySet().iterator(); it.hasNext(); ) {
213 Object b = it.next();
214 if (b.toString().endsWith('.' + blockName)) matches.add(b);
215 }
216 return matches;
217 }
218
219 private String readFile(Reader fr) throws IOException
220 {
221 StringBuffer content = new StringBuffer();
222 for (int c; (c = fr.read()) != -1; content.append((char)c));
223 fr.close();
224 return content.toString();
225 }
226
227 private void makeTree(String fileText)
228 {
229
230 if (!Pattern.compile(".*<!--\\s*BEGIN\\s*:\\s*main\\s*-->.*", Pattern.DOTALL)
231 .matcher(fileText).matches()) {
232 this.implicitMain = true;
233 fileText = "<!-- BEGIN: main -->" + fileText + "<!-- END: main -->";
234 }
235
236 Pattern pattern = Pattern.compile("<!--\\s*(BEGIN|END)\\s*:\\s*(\\w+)\\s*-->(.*?)(?=(?:<!--\\s*(?:BEGIN|END)\\s*:\\s*\\w+\\s*-->)|(?:\\s*$))", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
237 Matcher matcher = pattern.matcher(fileText);
238 ArrayList blockNames = new ArrayList();
239 String parentName = "";
240 int lastlength = 0;
241 while (matcher.find())
242 {
243
244 String after = matcher.group(3);
245 if (lastlength == 0 || fileText.charAt(matcher.start() - 1) == '\n') {
246 after = after.replaceFirst("^\\r?\\n", "");
247 }
248 lastlength = after.length();
249
250 if (matcher.group(1).toUpperCase().equals("BEGIN"))
251 {
252 parentName = implode(blockNames);
253 blockNames.add(matcher.group(2));
254 String currentBlockName = implode(blockNames);
255 if (blocks.containsKey(currentBlockName))
256 {
257 blocks.put(currentBlockName, blocks.get(currentBlockName) + after);
258 }
259 else
260 {
261 blocks.put(currentBlockName, after);
262 }
263 if (blocks.containsKey(parentName))
264 {
265 blocks.put(parentName, blocks.get(parentName) + "{_BLOCK_." + currentBlockName + "}");
266 }
267 else
268 {
269 blocks.put(parentName, "{_BLOCK_." + currentBlockName + "}");
270 }
271 subBlocks.put(parentName, currentBlockName);
272 subBlocks.put(currentBlockName, "");
273 }
274 else if (matcher.group(1).toUpperCase().equals("END"))
275 {
276 blockNames.remove(blockNames.size()-1);
277 parentName = implode(blockNames);
278 if (blocks.containsKey(parentName))
279 {
280 blocks.put(parentName, blocks.get(parentName) + after);
281 }
282 else
283 {
284 blocks.put(parentName, after);
285 }
286 }
287 }
288 }
289
290 private String implode(ArrayList al)
291 {
292 String ret = "";
293 for (int i = 0; al.size() > i; i++)
294 {
295 if (i != 0)
296 {
297 ret += ".";
298 }
299 ret += al.get(i);
300 }
301 return (ret);
302 }
303
304 }