View Javadoc

1   /*
2    * AbstractWikiReader.java Created on 27. květen 2004, 7:19
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          //    FIXME
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             // pop all on-stack elements that are deeper than the new one
117             doEndElement();
118             pop();
119         }
120         doStartElement(element, atts);
121         push(element);
122     }
123 
124     protected void endElementsOnStack() throws SAXException {
125         while (!isEmpty()) {
126             // pop all on-stack elements
127             doEndElement();
128             pop();
129         }
130     }
131 
132     protected void endElement() throws SAXException {
133         doEndElement();
134         // pop one element
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         // && (isNamechar(next) || next == '%')
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                     //boolean goOut = false;
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                             // %% - empty element
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                                 //r.pushback();
287                                 //System.out.println("not in text->step
288                                 // back="+r.at());
289                             }
290                             break;
291 
292                         } else if (isNamechar(c)) {
293 
294                             // nonempty element
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                             // to the next nonspace -> it will be attribute name
306                             c = r.nextNonspace(c);
307                             if (c == '{' || c == '%') {
308                                 // attrs are finished or nested tag encountered
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                                 // attrs are finished or nested tag encountered
339                                 e.startTag();
340                                 //                        }
341                             }
342                             // attrs to the elt on top.
343                         } else {
344                             // percent but not an element name
345                             isInText = true;
346                         }
347                     } while (c == '%' && !r.eof()); // && !goOut
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                     // normal char (not % { }) or % and not followed by element
362                     // name
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             // popping elts
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         //	 out.close();
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             //        System.out.println("creating elt="+name+", depth="+d);
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             //        System.out.println("attrs size="+attrs.size());
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             //    	System.err.println("pushing "+e.getName()+" depth="+e.depth());
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 }