1
2
3
4
5 package net.sf.tomp.pp.wiki;
6
7 import java.io.BufferedReader;
8 import java.io.IOException;
9 import java.util.ArrayList;
10 import java.util.List;
11
12 import net.sf.tomp.pp.AbstractXMLReader;
13 import net.sf.tomp.pp.CharReader;
14
15 import org.xml.sax.Attributes;
16 import org.xml.sax.InputSource;
17 import org.xml.sax.SAXException;
18 import org.xml.sax.helpers.AttributesImpl;
19
20 /***
21 * @author tomp
22 */
23 public abstract class AbstractWikiReader extends AbstractXMLReader {
24
25 private boolean verbose = true;
26
27 private List stack;
28
29 protected String top;
30
31 private String namespaceURI;
32
33 private String namespacePrefix;
34
35 protected static final AttributesImpl EMPTY_ATTRS = new AttributesImpl();
36
37 /*** Creates a new instance of AbstractWikiReader */
38 public AbstractWikiReader() {
39 stack = new ArrayList();
40 top = null;
41 namespaceURI = "";
42 namespacePrefix = "";
43 }
44
45 /***
46 * DOCUMENT ME!
47 *
48 * @param k DOCUMENT ME!
49 * @param v DOCUMENT ME!
50 */
51 public void setParameter(String k, Object v) {
52
53 }
54
55 public void parse(InputSource input) throws IOException, SAXException {
56 if (contentHandler == null) {
57 return;
58 }
59
60 BufferedReader br = getBufferedReader(input);
61
62 contentHandler.startDocument();
63 startElement(rootElement(), EMPTY_ATTRS);
64
65 String line = br.readLine();
66 while (line != null) {
67 System.out.println("Line:" + line);
68 process(line);
69 line = br.readLine();
70 }
71 endElementsOnStack();
72 contentHandler.endDocument();
73 }
74
75 protected abstract void process(String line) throws SAXException;
76
77 protected abstract String rootElement() throws SAXException;
78
79 protected void textElement(String element, String text) throws SAXException {
80 textElement(element, text, EMPTY_ATTRS);
81 }
82
83 protected void textElement(String element, String text, Attributes atts)
84 throws SAXException {
85 startElement(element, atts);
86 characters(text);
87 endElement();
88 }
89
90 protected void doStartElement(String element, Attributes atts)
91 throws SAXException {
92 if ("".equals(namespacePrefix))
93 contentHandler.startElement(namespaceURI, element, element, atts);
94 else
95 contentHandler.startElement(namespaceURI, element, namespacePrefix
96 + ":" + element, atts);
97 System.out.println("Element " + element + " started");
98 }
99
100 protected void doEndElement() throws SAXException {
101 if ("".equals(namespacePrefix))
102 contentHandler.endElement(namespaceURI, top, top);
103 else
104 contentHandler.endElement(namespaceURI, top, namespacePrefix + ":"
105 + top);
106 System.out.println("Element " + top + " ended");
107 }
108
109 protected void startElement(String element) throws SAXException {
110 startElement(element, EMPTY_ATTRS);
111 }
112
113 protected void startElement(String element, Attributes atts)
114 throws SAXException {
115 while (!isDeeperThan(top, element)) {
116
117 doEndElement();
118 pop();
119 }
120 doStartElement(element, atts);
121 push(element);
122 }
123
124 protected void endElementsOnStack() throws SAXException {
125 while (!isEmpty()) {
126
127 doEndElement();
128 pop();
129 }
130 }
131
132 protected void endElement() throws SAXException {
133 doEndElement();
134
135 pop();
136 }
137
138 protected void characters(String s) throws SAXException {
139 char[] cha = s.toCharArray();
140 contentHandler.characters(cha, 0, cha.length);
141 }
142
143 protected boolean isDeeperThan(String elt1, String elt2) {
144 if (elt1 == null)
145 return true;
146 else if (elt2 == null)
147 return false;
148 throw new IllegalArgumentException(
149 "Don't know how to compare depth of '" + elt1 + "' and '"
150 + elt2 + "'");
151 }
152
153 protected boolean isEmpty() {
154 return stack.isEmpty();
155 }
156
157 protected String top() {
158 return top;
159 }
160
161 protected void pop() {
162 stack.remove(stack.size() - 1);
163 if (stack.isEmpty())
164 top = null;
165 else
166 top = (String) stack.get(stack.size() - 1);
167 }
168
169 protected void push(String s) {
170 stack.add(s);
171 top = s;
172 }
173
174 public void closeNesting(EStack es, int depth) throws SAXException {
175 while (!es.isEmpty() && depth > 0) {
176 es.pop().endTag();
177 depth--;
178 }
179 }
180
181 public void closeNesting(EStack es) throws SAXException {
182 while (!es.isEmpty() && es.top().depth() > 0) {
183 es.pop().endTag();
184 }
185 if (!es.isEmpty())
186 es.pop().endTag();
187 }
188
189 public boolean markup(char c) {
190 return (c == '%') || c == '{' || c == '}' || c == '_' || c == '*'
191 || c == '[';
192
193 }
194
195 public boolean notMarkup(char c) {
196 return !markup(c);
197 }
198
199 public boolean isNamechar(char c) {
200 return Character.isLetterOrDigit(c) || c == '_' || c == ':' || c == '-'
201 || c == '.';
202 }
203
204 public boolean isWhitespace(char c) {
205 return Character.isWhitespace(c);
206 }
207
208 public boolean isQuote(char c) {
209 return c == '\'' || c == '"';
210 }
211
212 public boolean isTagMark(char c) {
213 return c == '%';
214 }
215
216 public void msg(String s) {
217 if (verbose)
218 System.err.print(s);
219 }
220
221 public void text(String s) throws SAXException {
222 characters(s);
223 }
224
225 protected static boolean isEmphasisBold(Element e) {
226 return e.getName().equals("emphasis")
227 && "bold".equals(e.attrs.getValue("role"));
228 }
229
230 protected static boolean isEmphasis(Element e) {
231 return e.getName().equals("emphasis")
232 && !"bold".equals(e.attrs.getValue("role"));
233 }
234
235 protected void processInline(String s) throws SAXException {
236 CharReader r = new CharReader(s);
237
238 EStack es = new EStack();
239 Element e = null;
240 boolean emptyElt = false;
241 boolean isInText = true;
242 int depth = 0;
243 int textBegin = r.index();
244 int afterName = 0;
245
246 try {
247 while (!r.eof()) {
248 textBegin = r.index();
249 char c = r.next();
250 if (c == '%' && (isNamechar(r.at()) || r.at() == '%')) {
251
252 do {
253 int afterPercent = r.index();
254 if (isInText && afterPercent - 1 > textBegin) {
255 text(r.substring(textBegin, afterPercent - 1));
256 }
257 isInText = false;
258 c = r.next();
259 if (c == '%') {
260
261
262 emptyElt = true;
263 c = r.next();
264 while (!r.eof() && isNamechar(c)) {
265 c = r.next();
266 }
267 afterName = r.eof() ? r.index() + 1 : r.index();
268 e = new Element(r.substring(afterPercent + 1,
269 afterName - 1), depth);
270 e.emptyTag();
271
272 r.pushback();
273
274 closeNesting(es, e.depth());
275
276 if (markup(r.at())) {
277 if (r.at() == '{')
278 isInText = true;
279 } else {
280 isInText = true;
281 }
282
283 if (isInText) {
284 textBegin = r.index();
285 } else {
286
287
288
289 }
290 break;
291
292 } else if (isNamechar(c)) {
293
294
295 c = r.next();
296 while (!r.eof() && isNamechar(c)) {
297 c = r.next();
298 }
299 afterName = r.eof() ? r.index() + 1 : r.index();
300 e = new Element(r.substring(afterPercent,
301 afterName - 1), depth);
302 es.push(e);
303 depth++;
304
305
306 c = r.nextNonspace(c);
307 if (c == '{' || c == '%') {
308
309 e.startTag();
310 } else {
311 while (!r.eof() && c != '{' && c != '%') {
312 int anBegin = r.index() - 1;
313 while (!r.eof() && c != '='
314 && !isWhitespace(c)) {
315 c = r.next();
316 }
317 e.newAttrName(r.substring(anBegin, r
318 .index() - 1));
319
320 while (!r.eof() && !isQuote(c)) {
321 c = r.next();
322 }
323 r.pushback();
324
325 char quote = r.next();
326 c = ' ';
327 int avBegin = r.index();
328 while (!r.eof() && c != quote) {
329 c = r.next();
330 }
331 e.newAttrValue(r.substring(avBegin, r
332 .index() - 1));
333
334 c = r.next();
335 c = r.nextNonspace(c);
336
337 }
338
339 e.startTag();
340
341 }
342
343 } else {
344
345 isInText = true;
346 }
347 } while (c == '%' && !r.eof());
348
349 depth = 0;
350
351 } else if (c == '{') {
352 e = new Brackets();
353 es.push(e);
354 e.startTag();
355
356 } else if (c == '}') {
357 closeNesting(es);
358 isInText = true;
359
360 } else {
361
362
363
364 if (c == '%' && !r.eof()) {
365 c = r.next();
366 }
367
368 while (!r.eof() && notMarkup(c)) {
369 c = r.next();
370 }
371 r.pushback();
372 int firstMarkup = r.eof() ? r.index() + 1 : r.index();
373 text(r.substring(textBegin, firstMarkup));
374 }
375 }
376
377 while (!es.isEmpty()) {
378 es.pop().endTag();
379 }
380
381 } catch (StringIndexOutOfBoundsException aioob) {
382 while (!es.isEmpty()) {
383 es.pop().endTag();
384 }
385 }
386
387 }
388
389 protected class Element {
390
391 private String name;
392
393 private AttributesImpl attrs;
394
395 private String attrName, attrValue;
396
397 private char avDelim;
398
399 private int depth;
400
401 public Element(String name) {
402 attrs = new AttributesImpl();
403 this.name = name;
404 }
405
406 public Element(String name, int d) {
407 this(name);
408 this.depth = d;
409
410 }
411
412 public void newAttrName(String name) {
413 attrName = name;
414 }
415
416 public void newAttrValue(String value) {
417 attrValue = value;
418 addAttribute();
419 }
420
421 protected void addAttribute() {
422 attrs.addAttribute("", attrName, attrName, "CDATA", attrValue);
423
424 }
425
426 public void startTag() throws SAXException {
427 startElement(name, attrs);
428 }
429
430 public void endTag() throws SAXException {
431 endElement();
432 }
433
434 public void emptyTag() throws SAXException {
435 startTag();
436 endTag();
437 }
438
439 public int depth() {
440 return depth;
441 }
442
443 public String getName() {
444 return name;
445 }
446 }
447
448 protected class Brackets extends Element {
449
450 public Brackets() {
451 super("{");
452 }
453
454 public void startTag() throws SAXException {
455 characters("{");
456 }
457
458 public void endTag() throws SAXException {
459 characters("}");
460 }
461
462 public void emptyTag() throws SAXException {
463 characters("{");
464 }
465
466 }
467
468 public class EStack {
469
470 List st = new ArrayList();
471
472 public void push(Element e) {
473
474 st.add(e);
475 }
476
477 public Element pop() {
478 int top = st.size() - 1;
479 Element e = (Element) st.remove(top);
480 return e;
481 }
482
483 public Element top() {
484 int top = st.size() - 1;
485 Element e = (Element) st.get(top);
486 return e;
487 }
488
489 public boolean isEmpty() {
490 return st.isEmpty();
491 }
492 }
493 }