View Javadoc

1   /*
2    * AbstractWikiReader.java
3    *
4    * Created on 27. květen 2004, 7:19
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          //    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) 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             // 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) 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         // && (isNamechar(next) || next == '%')
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                     //boolean goOut = false;
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                             // %% - empty element
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                                 //r.pushback();
282                                 //System.out.println("not in text->step back="+r.at());
283                             }
284                             break;
285                             
286                         } else if (isNamechar(c)) {
287                             
288                             // nonempty element
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                             // to the next nonspace -> it will be attribute name
299                             c = r.nextNonspace(c);
300                             if (c == '{' || c == '%') {
301                                 // attrs are finished or nested tag encountered
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                                 // attrs are finished or nested tag encountered
329                                 e.startTag();
330                                 //                        }
331                             }
332                             // attrs to the elt on top.
333                         } else {
334                             // percent but not an element name
335                             isInText = true;
336                         }
337                     } while(c == '%' && !r.eof()); // && !goOut
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                     // normal char (not  % { }) or % and not followed by element name
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             // popping elts
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         //	 out.close();
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             //        System.out.println("creating elt="+name+", depth="+d);
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             //        System.out.println("attrs size="+attrs.size());
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             //    	System.err.println("pushing "+e.getName()+" depth="+e.depth());
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 }