1
2
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
110 startTitledElement("!foilgroup" + line.substring(3));
111 } else if (line.startsWith("---")) {
112
113 startTitledElement("!foil" + line.substring(3));
114 } else if (line.startsWith("*")) {
115
116 itemizedlistItem(line);
117 } else if (line.startsWith("#")) {
118
119 orderedlistItem(line);
120 } else if (line.startsWith("!mediaobject")
121 || line.startsWith("!figure")) {
122 startTitledFiledElement(line);
123 } else if (line.startsWith("!")) {
124
125 startTitledElement(line);
126 } else if (line.startsWith("{{{")) {
127
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
136 endElement();
137 inProgramlisting = false;
138 } else if (line.startsWith(";")) {
139
140 variableListItem(line);
141 } else if (line.equals("")) {
142
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
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
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
294 startElement(element, atts);
295 processInline(text);
296 endElement();
297 }
298
299 protected void processedTextElement(String element, String text)
300 throws SAXException {
301
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
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
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
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
387 c = r.nextNonspace(c);
388 if (c == '{' || c == '%') {
389
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
420 e.startTag();
421
422 }
423
424 } else {
425
426 isInText = true;
427 }
428 } while (c == '%' && !r.eof());
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
445 e = new Element("emphasis");
446 e.newAttrName("role");
447 e.newAttrValue("bold");
448 es.push(e);
449 e.startTag();
450 } else {
451
452 es.pop().endTag();
453 }
454 } else {
455 text("*");
456 }
457 c = r.next();
458
459 } else if (c == '_') {
460 if (r.at() == '_') {
461
462 if (es.isEmpty() || !isEmphasis(es.top())) {
463
464 e = new Element("emphasis");
465 es.push(e);
466 e.startTag();
467 } else {
468
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
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
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
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
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
574
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
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
599 }
600
601 public boolean markup(char c) {
602 return (c == '|') || (c == '@') || super.markup(c);
603 }
604 }