View Javadoc

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