View Javadoc

1   /*
2    * DocBookSlidesWikiReader.java
3    *
4    * Created on 27. květen 2004, 7:35
5    */
6   
7   package net.sf.tomp.pp.wiki.docbook;
8   
9   import java.util.HashMap;
10  import java.util.Map;
11  import java.util.regex.Matcher;
12  import java.util.regex.Pattern;
13  
14  import net.sf.tomp.pp.CharReader;
15  import net.sf.tomp.pp.wiki.AbstractWikiReader;
16  
17  import org.xml.sax.Attributes;
18  import org.xml.sax.SAXException;
19  import org.xml.sax.helpers.AttributesImpl;
20  
21  /***
22   * TODO: nested lists, inline elements
23   * @author  tomp
24   */
25  public class DocBookSlidesWikiReader extends AbstractWikiReader {
26      
27      private String inList = null;
28      private boolean inProgramlisting = false;
29      
30      private static Map ELEMENTS = new HashMap();
31      
32      protected static void depth(String elt, int depth) {
33          ELEMENTS.put(elt, new Integer(depth));
34      }    
35  
36      protected int getDepth(String elt) {
37          Integer ii = (Integer)ELEMENTS.get(elt);
38          if (ii == null) return -1;
39          return ii.intValue();
40      }    
41      
42      static {
43          depth("slides", 0);
44          depth("foilgroup", 1);
45          depth("foil", 2);
46          
47          depth("title", 3);
48          
49          depth("programlisting", 5);
50          
51          depth("itemizedlist", 5);
52          depth("orderedlist", 5); 
53          depth("variablelist", 5); 
54          
55          depth("varlistentry", 6); 
56  
57          depth("term", 7); 
58          depth("listitem", 7); 
59  
60          depth("tip", 5);
61          depth("warning",  5);
62          depth("note",  5);
63          depth("caution",  5);
64          depth("important",  5);
65          depth("sidebar", 5);
66          depth("abstract", 5);
67          depth("footnote", 5);
68          
69          depth("para", 8);
70  
71          depth("simpara", 9);
72          
73          depth("figure", 3);
74          
75          depth("mediaobject", 4);
76          depth("caption", 5);
77          depth("imageobject", 5);
78          
79          depth("ulink", 20);
80          depth("xref", 20);
81          depth("emphasis", 20);
82          
83          depth("classname", 21);
84          depth("packagename", 21);
85          depth("methodname", 21);
86      };
87      
88      protected boolean isDeeperThan(String elt1, String elt2) {
89          if(elt1 == null || elt2 == null)
90              return super.isDeeperThan(elt1, elt2);
91          
92          if(top.equals("foilgroup") && elt1.equals("foil")
93              && elt2.equals("title")) return false;
94          
95          if(elt1.equals("figure") && elt2.equals("title")) 
96              return true;
97          
98          int i1 = getDepth(elt1);
99          int i2 = getDepth(elt2);
100         if(i1 == -1 || i2 == -1)
101             return super.isDeeperThan(elt1, elt2);
102         return i1 < i2;
103     }
104     
105     protected void process(String line)  throws SAXException {
106         if(line.startsWith("===")) {
107             // foilgroup begin & title
108             startTitledElement("!foilgroup"+line.substring(3));
109         } else if(line.startsWith("---")) {
110             // foil begin, id & title
111             startTitledElement("!foil"+line.substring(3));
112         } else if(line.startsWith("*")) {
113             // itemizedlist listitem
114             itemizedlistItem(line);
115         } else if(line.startsWith("#")) {
116             // orderedlist listitem
117             orderedlistItem(line);
118         } else if(line.startsWith("!mediaobject")
119                || line.startsWith("!figure")
120                ) {
121             startTitledFiledElement(line);
122         } else if(line.startsWith("!")) {
123             // tip, caution, important, note, warning, sidebar,...
124             startTitledElement(line);
125         } else if(line.startsWith("{{{")) {
126             // programlisting begin
127             inProgramlisting = true;
128             AttributesImpl atts = new AttributesImpl();
129             if(line.length()>3) {
130                 atts.addAttribute("", "id", "id", "CDATA", line.substring(3));
131             }
132             startElement("programlisting", atts);
133         } else if(line.startsWith("}}}")) {
134             // programlisting end
135             endElement();
136             inProgramlisting = false;
137         } else if(line.startsWith(";")) {
138             // definitionlist
139             variableListItem(line);
140         } else if(line.equals("")) {
141             // empty line
142             emptyLine();
143         } else {
144             if(inProgramlisting)
145                 characters(line+"\n");
146             else
147                 processedTextElement("para", line);
148         }
149     }
150     
151     protected void emptyLine() throws SAXException {
152         inList = null;
153         while(top != null 
154         && (top.endsWith("para") 
155             || top.endsWith("entry") 
156             || top.endsWith("item") 
157             || top.endsWith("list"))) {
158             endElement();
159         }
160     }
161     
162     protected static final Pattern VARLIST_ITEM 
163         = Pattern.compile("^//;([^//:]+)//:(.*)");
164     
165     protected void variableListItem(String line) throws SAXException  {
166         Matcher m = VARLIST_ITEM.matcher(line);
167         if(m.matches()) {
168             if(!"variablelist".equals(inList)) {
169                 inList = "variablelist";
170                 startElement(inList);
171             }
172             System.out.println("matched in "+line);
173             String terms = m.group(1);
174             String definition = m.group(2);
175             startElement("varlistentry");
176             // TODO: no multiple terms yet
177             processedTextElement("term", terms);
178             startElement("listitem");
179             processedTextElement("simpara", definition);
180         }
181     }
182     
183     protected void listItem(String listType, String line) throws SAXException  {
184         if(!listType.equals(inList)) {
185             startElement(listType+"list");
186             inList = listType;
187         }
188         startElement("listitem");
189         processedTextElement("simpara", line.substring(1));
190     }
191     
192     protected void itemizedlistItem(String line) throws SAXException  {
193         listItem("itemized", line);
194     }
195     
196     protected void orderedlistItem(String line) throws SAXException  {
197         listItem("ordered", line);
198     }
199     
200     protected static final String ID_TITLE 
201         = "(//#(//S*))?//s*(.*)";
202     
203     protected static final String ELEMENT_ID_TITLE 
204         = "//!(//w+)"+ID_TITLE;
205     
206     protected static final Pattern P_ELEMENT_ID_TITLE 
207         = Pattern.compile(ELEMENT_ID_TITLE);
208     
209     protected void startTitledElement(String line) throws SAXException  {
210         System.out.println("startTitledElement "+line);
211         Matcher m = P_ELEMENT_ID_TITLE.matcher(line);
212         if(m.matches()) {
213             String element = m.group(1);
214             String id = m.group(3);
215             String title = m.group(4);
216             startTitledElement(element, id, title);
217         }
218     }
219 
220     protected static final String ELEMENT_ID_FILE_TITLE 
221         = "//!(//w+)(//#(//S*))?//s*(//S+)//s+(.*)";
222     
223     protected static final Pattern P_ELEMENT_ID_FILE_TITLE 
224         = Pattern.compile(ELEMENT_ID_FILE_TITLE);
225     
226     protected void startTitledFiledElement(String line) throws SAXException  {
227         System.out.println("startTitledFiledElement "+line);
228         Matcher m = P_ELEMENT_ID_FILE_TITLE.matcher(line);
229         if(m.matches()) {
230             String element = m.group(1);
231             String id = m.group(3);
232             String file = m.group(4);
233             String title = m.group(5);
234             startTitledFiledElement(element, id, title, file);
235         }
236     }
237 
238     protected AttributesImpl getAttributesWithId(String id) {
239         if(id != null && id.length() > 0) {
240             AttributesImpl atts = new AttributesImpl();
241             atts.addAttribute("", "id", "id", "CDATA", id);
242             return atts;
243         } else {
244             return EMPTY_ATTRS;
245         }
246     }
247     
248     protected void startTitledElement(String element, String id, String title)
249     throws SAXException  {
250         System.out.println("startTitledElement "+element+" id="+id+" title="+title);
251         startElement(element, getAttributesWithId(id));
252         if(   element.equals("foilgroup")
253            || element.equals("foil")
254           ) {
255             textElement("title", title);
256         } else {
257             // tip, note, warning, important, sidebar, caution, ... abstract
258             processedTextElement("simpara", title);
259         }
260         if(element.equals("footnote")
261         || element.equals("abstract")
262         ) {
263             endElement();
264         }
265     }
266     
267     protected void startTitledFiledElement(String element, String id, String title, String file)
268     throws SAXException  {
269         System.out.println("startTitledFiledElement "+element+" id="+id
270             +" title="+title+" file="+file);
271         
272         if(element.equals("figure")) {
273             
274             startElement("figure", getAttributesWithId(id));
275             textElement("title", title);
276             startElement("mediaobject");
277             AttributesImpl atts2 = new AttributesImpl();
278             atts2.addAttribute("", "fileref", "fileref", "CDATA", file);
279             startElement("imageobject", atts2);
280             endElement();
281             endElement();
282             endElement();
283             
284         } else if(element.equals("mediaobject")) {
285             
286             startElement("mediaobject", getAttributesWithId(id));
287             AttributesImpl atts2 = new AttributesImpl();
288             atts2.addAttribute("", "fileref", "fileref", "CDATA", file);
289             startElement("imageobject", atts2);
290             startElement("caption");
291             textElement("para", title);
292             endElement();
293             endElement();
294             endElement();
295         }
296     }
297     
298     protected void processedTextElement(String element, String text, Attributes atts)
299      throws SAXException {
300         // FIXME parsing of a line
301         startElement(element, atts);
302         processInline(text);
303         endElement();
304     }
305     
306     protected void processedTextElement(String element, String text) 
307      throws SAXException {
308         // FIXME parsing of a line
309         processedTextElement(element, text, EMPTY_ATTRS);
310     }
311     
312     protected int listDepth(String line) {
313         if(line.startsWith("*") || line.startsWith("#"))
314             return 1 + listDepth(line.substring(1));
315         else 
316             return 0;
317     }    
318 
319     public void setParameter(String k, Object v) {
320     }
321     
322     protected String rootElement() throws SAXException {
323         return "slides";
324     }
325     
326     protected void processInline(String s) throws SAXException {
327         CharReader r = new CharReader(s);
328         
329         EStack es = new EStack();
330         Element e = null;
331         boolean emptyElt = false;
332         boolean isInText = true;
333         int depth = 0;
334         int textBegin = r.index();
335         int afterName = 0;
336         
337         try {
338             while(!r.eof()) {
339                 textBegin = r.index();
340                 char c = r.next();
341                 if (c == '%' && (isNamechar(r.at()) || r.at() == '%')) {
342                     //boolean goOut = false;
343                     do {
344                         int afterPercent = r.index();
345                         if (isInText && afterPercent-1 > textBegin) {
346                             text(r.substring(textBegin, afterPercent-1));
347                         }
348                         isInText = false;
349                         c = r.next();
350                         if (c == '%') {
351                             
352                             // %% - empty element
353                             emptyElt = true;
354                             c = r.next();
355                             while(!r.eof() && isNamechar(c)) {
356                                 c = r.next();
357                             }
358                             afterName = r.eof() ? r.index()+1 : r.index();
359                             e = new Element(r.substring(afterPercent+1, afterName-1), depth);
360                             e.emptyTag();
361                             
362                             r.pushback();
363                             
364                             closeNesting(es, e.depth());
365                             
366                             if(markup(r.at())) {
367                                 if(r.at() == '{') {
368                                     isInText = true;
369                                 }
370                             } else {
371                                 isInText = true;
372                             }
373                             
374                             if(isInText) {
375                                 textBegin = r.index();
376                             }
377                             break;
378                             
379                         } else if (isNamechar(c)) {
380                             
381                             // nonempty element
382                             c = r.next();
383                             while(!r.eof() && isNamechar(c)) {
384                                 c = r.next();
385                             }
386                             afterName = r.eof() ? r.index()+1 : r.index();
387                             e = new Element(r.substring(afterPercent, afterName-1), depth);
388                             es.push(e);
389                             depth++;
390                             
391                             // to the next nonspace -> it will be attribute name
392                             c = r.nextNonspace(c);
393                             if (c == '{' || c == '%') {
394                                 // attrs are finished or nested tag encountered
395                                 e.startTag();
396                             } else {
397                                 while(!r.eof() && c != '{' && c != '%') {
398                                     int anBegin = r.index()-1;
399                                     while(!r.eof() && c != '=' && !isWhitespace(c)) {
400                                         c = r.next();
401                                     }
402                                     e.newAttrName(r.substring(anBegin, r.index()-1));
403                                     
404                                     while(!r.eof() && !isQuote(c)) {
405                                         c = r.next();
406                                     }
407                                     r.pushback();
408                                     
409                                     char quote = r.next();
410                                     c = ' ';
411                                     int avBegin = r.index();
412                                     while(!r.eof() && c != quote) {
413                                         c = r.next();
414                                     }
415                                     e.newAttrValue(r.substring(avBegin, r.index()-1));
416                                     
417                                     c = r.next();
418                                     c = r.nextNonspace(c);
419                                     
420                                 }
421                                 // attrs are finished or nested tag encountered
422                                 e.startTag();
423                                 //                        }
424                             }
425                             // attrs to the elt on top.
426                         } else {
427                             // percent but not an element name
428                             isInText = true;
429                         }
430                     } while(c == '%' && !r.eof()); // && !goOut
431                     
432                     depth = 0;
433                     
434                 } else if (c == '{') {
435                     e = new Brackets();
436                     es.push(e);
437                     e.startTag();
438                     
439                 } else if (c == '}') {
440                     closeNesting(es);
441                     isInText = true;
442                     
443                 } else if (c == '*') {
444                     if(r.at() == '*') {
445                         if(es.isEmpty() || !isEmphasisBold(es.top()))  {
446                             // 'emphasis/bold' to be pushed
447                             e = new Element("emphasis");
448                             e.newAttrName("role");
449                             e.newAttrValue("bold");
450                             es.push(e);
451                             e.startTag();
452                         } else {
453                             // 'emphasis' to be popped
454                             es.pop().endTag();
455                         }
456                     } else {
457                         text("*");
458                     }
459                     c = r.next();
460                 
461                 } else if (c == '_') {
462                     if (r.at() == '_') {
463                         //System.out.println("Emphasis");
464                         if(es.isEmpty() || !isEmphasis(es.top()))  {
465                             // 'emphasis' to be pushed
466                             e = new Element("emphasis");
467                             es.push(e);
468                             e.startTag();
469                         } else {
470                             // 'emphasis' to be popped
471                             es.pop().endTag();
472                         }
473                     } else {
474                         text("_");
475                     }
476                     c = r.next();
477 
478                 } else if (c == '[') {
479                     if(r.at() == '[') {
480                         text("[");
481                         c = r.next();
482                     } else {
483                         c = r.next();
484                         System.out.println("link begin");
485                         boolean xref = false;
486 
487                         String text = "";
488                         
489                         int textStart = r.index();
490                         // until | or ] not reached
491                         while(!r.eof() && c != '|' && c != ']') {
492                             c = r.next();
493                         }
494                         int textEnd = r.index();
495                         text = r.substring(textStart-1, textEnd-1);
496                         if(c == '|') {
497                             // text now, url will be specified
498                             while(!r.eof() && c != ']') {
499                                 c = r.next();
500                             }
501                             int urlEnd = r.index();
502                             String url = r.substring(textEnd, urlEnd-1);
503 
504                             xref = url.startsWith(">>>");
505                             if(xref) {
506                                 e = new Element("xref");
507                                 e.newAttrName("linkend");
508                                 e.newAttrValue(url.substring(3));
509                                 e.newAttrName("endterm");
510                                 e.newAttrValue(text);
511                             } else {    
512                                 e = new Element("ulink");
513                                 e.newAttrName("url");
514                                 e.newAttrValue(url);
515                             }
516                             es.push(e);
517                             
518                         } else {
519                             xref = text.startsWith(">>>");
520                             if(xref) {
521                                 e = new Element("xref");
522                                 e.newAttrName("linkend");
523                                 e.newAttrValue(text.substring(3));
524                             } else {    
525                                 e = new Element("ulink");
526                                 e.newAttrName("url");
527                                 e.newAttrValue(text);
528                             }
529                             es.push(e);
530                         }
531                         e.startTag();
532                         if(!xref)
533                             text(text);
534                         es.pop().endTag();
535                     }
536 
537                 } else if (c == '@') {
538                     if(isWhitespace(r.at(r.index()-2)) && isNamechar(r.at())) {
539                         c = r.next();
540                         System.out.println("@name");
541 
542                         int eltnameStart = r.index();
543                         // until space not reached
544                         while(!r.eof() && c != ' ') {
545                             c = r.next();
546                         }
547                         int eltnameEnd = r.index();
548                         String eltname = r.substring(eltnameStart-1, eltnameEnd-1);
549 
550                         // eltname has been read, name will follow
551                         while(!r.eof() && isWhitespace(c)) {
552                             c = r.next();
553                         }
554                         int nameStart = r.index()-1;
555                         while(!r.eof() && (isNamechar(c) || c == '\'' 
556                             || c == '[' || c == ']'
557                             || c == '(' || c == ')')) {
558                             c = r.next();
559                         }
560                         int nameEnd = r.index();
561                         String name = r.substring(nameStart, nameEnd-1);
562 
563                         e = new Element(eltname+"name");
564                         es.push(e);
565                         e.startTag();
566                         name = name.replace('\'', ' '); 
567                         text(name);
568                         es.pop().endTag();
569                     } else {
570                         c = r.next();
571                         text("@"+c);
572                     }
573                 } else {
574                     // normal char (not  % { }) or % and not followed by element name
575                     
576                     if (c == '%' && !r.eof()) {
577                         c = r.next();
578                     }
579                     
580                     while(!r.eof() && notMarkup(c)) {
581                         c = r.next();
582                     }
583                     r.pushback();
584                     int firstMarkup = r.eof() ? r.index()+1 : r.index();
585                     text(r.substring(textBegin, firstMarkup));
586                 }
587             }
588             // popping elts
589             while(!es.isEmpty()) {
590                 es.pop().endTag();
591             }
592             
593         } catch(StringIndexOutOfBoundsException aioob) {
594             while(!es.isEmpty()) {
595                 es.pop().endTag();
596             }
597         }
598         //	 out.close();
599     }
600     
601     public boolean markup(char c) {
602         return (c == '|' ) || (c == '@' ) || super.markup(c);
603     }
604 }