1
2
3
4
5
6
7 package net.sf.tomp.pp.wiki;
8
9 import java.io.BufferedReader;
10 import java.io.IOException;
11 import java.util.ArrayList;
12 import java.util.List;
13
14 import net.sf.tomp.pp.AbstractXMLReader;
15 import net.sf.tomp.pp.CharReader;
16
17 import org.xml.sax.Attributes;
18 import org.xml.sax.InputSource;
19 import org.xml.sax.SAXException;
20 import org.xml.sax.helpers.AttributesImpl;
21
22
23 /***
24 *
25 * @author tomp
26 */
27 public abstract class AbstractWikiReader extends AbstractXMLReader {
28
29 private boolean verbose = true;
30
31 private List stack;
32 protected String top;
33 private String namespaceURI;
34 private String namespacePrefix;
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) throws SAXException {
91 if("".equals(namespacePrefix))
92 contentHandler.startElement(namespaceURI, element,
93 element, atts);
94 else
95 contentHandler.startElement(namespaceURI, element,
96 namespacePrefix + ":" + 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,
103 top);
104 else
105 contentHandler.endElement(namespaceURI, top,
106 namespacePrefix + ":" + top);
107 System.out.println("Element "+top+" ended");
108 }
109
110 protected void startElement(String element) throws SAXException {
111 startElement(element, EMPTY_ATTRS);
112 }
113
114 protected void startElement(String element, Attributes atts) 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) return true;
145 else if(elt2 == null) return false;
146 throw new IllegalArgumentException(
147 "Don't know how to compare depth of '"
148 + elt1 + "' and '" + elt2 + "'");
149 }
150
151 protected boolean isEmpty() {
152 return stack.isEmpty();
153 }
154
155 protected String top() {
156 return top;
157 }
158
159 protected void pop() {
160 stack.remove(stack.size()-1);
161 if(stack.isEmpty())
162 top = null;
163 else
164 top = (String)stack.get(stack.size()-1);
165 }
166
167 protected void push(String s) {
168 stack.add(s);
169 top = s;
170 }
171
172 public void closeNesting(EStack es, int depth) throws SAXException {
173 while (!es.isEmpty() && depth > 0) {
174 es.pop().endTag();
175 depth--;
176 }
177 }
178
179 public void closeNesting(EStack es) throws SAXException {
180 while (!es.isEmpty() && es.top().depth() > 0) {
181 es.pop().endTag();
182 }
183 if (!es.isEmpty()) es.pop().endTag();
184 }
185
186 public boolean markup(char c) {
187 return (c == '%' ) || c == '{' || c == '}'
188 || c == '_' || c == '*' || c == '[';
189
190 }
191
192 public boolean notMarkup(char c) {
193 return !markup(c);
194 }
195
196 public boolean isNamechar(char c) {
197 return Character.isLetterOrDigit(c) || c == '_' || c == ':' || c == '-' || c == '.';
198 }
199
200 public boolean isWhitespace(char c) {
201 return Character.isWhitespace(c);
202 }
203
204 public boolean isQuote(char c) {
205 return c == '\'' || c == '"';
206 }
207
208 public boolean isTagMark(char c) {
209 return c == '%';
210 }
211
212 public void msg(String s) {
213 if (verbose)
214 System.err.print(s);
215 }
216
217 public void text(String s) throws SAXException {
218 characters(s);
219 }
220
221 protected static boolean isEmphasisBold(Element e) {
222 return e.getName().equals("emphasis")
223 && "bold".equals(e.attrs.getValue("role"));
224 }
225
226 protected static boolean isEmphasis(Element e) {
227 return e.getName().equals("emphasis")
228 && !"bold".equals(e.attrs.getValue("role"));
229 }
230
231 protected void processInline(String s) throws SAXException {
232 CharReader r = new CharReader(s);
233
234 EStack es = new EStack();
235 Element e = null;
236 boolean emptyElt = false;
237 boolean isInText = true;
238 int depth = 0;
239 int textBegin = r.index();
240 int afterName = 0;
241
242 try {
243 while(!r.eof()) {
244 textBegin = r.index();
245 char c = r.next();
246 if (c == '%' && (isNamechar(r.at()) || r.at() == '%')) {
247
248 do {
249 int afterPercent = r.index();
250 if (isInText && afterPercent-1 > textBegin) {
251 text(r.substring(textBegin, afterPercent-1));
252 }
253 isInText = false;
254 c = r.next();
255 if (c == '%') {
256
257
258 emptyElt = true;
259 c = r.next();
260 while(!r.eof() && isNamechar(c)) {
261 c = r.next();
262 }
263 afterName = r.eof() ? r.index()+1 : r.index();
264 e = new Element(r.substring(afterPercent+1, afterName-1), depth);
265 e.emptyTag();
266
267 r.pushback();
268
269 closeNesting(es, e.depth());
270
271 if(markup(r.at())) {
272 if(r.at() == '{')
273 isInText = true;
274 } else {
275 isInText = true;
276 }
277
278 if(isInText) {
279 textBegin = r.index();
280 } else {
281
282
283 }
284 break;
285
286 } else if (isNamechar(c)) {
287
288
289 c = r.next();
290 while(!r.eof() && isNamechar(c)) {
291 c = r.next();
292 }
293 afterName = r.eof() ? r.index()+1 : r.index();
294 e = new Element(r.substring(afterPercent, afterName-1), depth);
295 es.push(e);
296 depth++;
297
298
299 c = r.nextNonspace(c);
300 if (c == '{' || c == '%') {
301
302 e.startTag();
303 } else {
304 while(!r.eof() && c != '{' && c != '%') {
305 int anBegin = r.index()-1;
306 while(!r.eof() && c != '=' && !isWhitespace(c)) {
307 c = r.next();
308 }
309 e.newAttrName(r.substring(anBegin, r.index()-1));
310
311 while(!r.eof() && !isQuote(c)) {
312 c = r.next();
313 }
314 r.pushback();
315
316 char quote = r.next();
317 c = ' ';
318 int avBegin = r.index();
319 while(!r.eof() && c != quote) {
320 c = r.next();
321 }
322 e.newAttrValue(r.substring(avBegin, r.index()-1));
323
324 c = r.next();
325 c = r.nextNonspace(c);
326
327 }
328
329 e.startTag();
330
331 }
332
333 } else {
334
335 isInText = true;
336 }
337 } while(c == '%' && !r.eof());
338
339 depth = 0;
340
341 } else if (c == '{') {
342 e = new Brackets();
343 es.push(e);
344 e.startTag();
345
346 } else if (c == '}') {
347 closeNesting(es);
348 isInText = true;
349
350 } else {
351
352
353 if (c == '%' && !r.eof()) {
354 c = r.next();
355 }
356
357 while(!r.eof() && notMarkup(c)) {
358 c = r.next();
359 }
360 r.pushback();
361 int firstMarkup = r.eof() ? r.index()+1 : r.index();
362 text(r.substring(textBegin, firstMarkup));
363 }
364 }
365
366 while(!es.isEmpty()) {
367 es.pop().endTag();
368 }
369
370 } catch(StringIndexOutOfBoundsException aioob) {
371 while(!es.isEmpty()) {
372 es.pop().endTag();
373 }
374 }
375
376 }
377
378 protected class Element {
379
380 private String name;
381 private AttributesImpl attrs;
382
383 private String attrName, attrValue;
384 private char avDelim;
385 private int depth;
386
387 public Element(String name) {
388 attrs = new AttributesImpl();
389 this.name = name;
390 }
391
392 public Element(String name, int d) {
393 this(name);
394 this.depth = d;
395
396 }
397
398 public void newAttrName(String name) {
399 attrName = name;
400 }
401
402 public void newAttrValue(String value) {
403 attrValue = value;
404 addAttribute();
405 }
406
407 protected void addAttribute() {
408 attrs.addAttribute("", attrName, attrName, "CDATA", attrValue);
409
410 }
411
412 public void startTag() throws SAXException {
413 startElement(name, attrs);
414 }
415
416 public void endTag() throws SAXException {
417 endElement();
418 }
419
420 public void emptyTag() throws SAXException {
421 startTag();
422 endTag();
423 }
424
425 public int depth() {
426 return depth;
427 }
428
429 public String getName() {
430 return name;
431 }
432 }
433
434 protected class Brackets extends Element {
435
436 public Brackets() {
437 super("{");
438 }
439
440 public void startTag() throws SAXException {
441 characters("{");
442 }
443
444 public void endTag() throws SAXException {
445 characters("}");
446 }
447
448 public void emptyTag() throws SAXException {
449 characters("{");
450 }
451
452 }
453
454 public class EStack {
455
456 List st = new ArrayList();
457
458 public void push(Element e) {
459
460 st.add(e);
461 }
462
463 public Element pop() {
464 int top = st.size()-1;
465 Element e = (Element)st.remove(top);
466 return e;
467 }
468
469 public Element top() {
470 int top = st.size()-1;
471 Element e = (Element)st.get(top);
472 return e;
473 }
474
475 public boolean isEmpty() {
476 return st.isEmpty();
477 }
478 }
479 }