1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 package org.nuiton.jrst.legacy;
36
37 import static org.nuiton.i18n.I18n.t;
38 import static org.nuiton.jrst.legacy.ReStructuredText.ADDRESS;
39 import static org.nuiton.jrst.legacy.ReStructuredText.ADMONITION;
40 import static org.nuiton.jrst.legacy.ReStructuredText.ATTRIBUTION;
41 import static org.nuiton.jrst.legacy.ReStructuredText.AUTHOR;
42 import static org.nuiton.jrst.legacy.ReStructuredText.AUTHORS;
43 import static org.nuiton.jrst.legacy.ReStructuredText.BLOCK_QUOTE;
44 import static org.nuiton.jrst.legacy.ReStructuredText.BULLET_LIST;
45 import static org.nuiton.jrst.legacy.ReStructuredText.COLSPEC;
46 import static org.nuiton.jrst.legacy.ReStructuredText.COMMENT;
47 import static org.nuiton.jrst.legacy.ReStructuredText.CONTACT;
48 import static org.nuiton.jrst.legacy.ReStructuredText.COPYRIGHT;
49 import static org.nuiton.jrst.legacy.ReStructuredText.DATE;
50 import static org.nuiton.jrst.legacy.ReStructuredText.DECORATION;
51 import static org.nuiton.jrst.legacy.ReStructuredText.DEFINITION;
52 import static org.nuiton.jrst.legacy.ReStructuredText.DEFINITION_LIST;
53 import static org.nuiton.jrst.legacy.ReStructuredText.DEFINITION_LIST_ITEM;
54 import static org.nuiton.jrst.legacy.ReStructuredText.DESCRIPTION;
55 import static org.nuiton.jrst.legacy.ReStructuredText.DOCINFO;
56 import static org.nuiton.jrst.legacy.ReStructuredText.DOCTEST_BLOCK;
57 import static org.nuiton.jrst.legacy.ReStructuredText.DOCUMENT;
58 import static org.nuiton.jrst.legacy.ReStructuredText.EMPHASIS;
59 import static org.nuiton.jrst.legacy.ReStructuredText.ENTRY;
60 import static org.nuiton.jrst.legacy.ReStructuredText.ENUMERATED_LIST;
61 import static org.nuiton.jrst.legacy.ReStructuredText.FIELD;
62 import static org.nuiton.jrst.legacy.ReStructuredText.FIELD_BODY;
63 import static org.nuiton.jrst.legacy.ReStructuredText.FIELD_LIST;
64 import static org.nuiton.jrst.legacy.ReStructuredText.FIELD_NAME;
65 import static org.nuiton.jrst.legacy.ReStructuredText.FOOTER;
66 import static org.nuiton.jrst.legacy.ReStructuredText.FOOTNOTE;
67 import static org.nuiton.jrst.legacy.ReStructuredText.FOOTNOTE_REFERENCE;
68 import static org.nuiton.jrst.legacy.ReStructuredText.FOOTNOTE_SYMBOL;
69 import static org.nuiton.jrst.legacy.ReStructuredText.GENERATED;
70 import static org.nuiton.jrst.legacy.ReStructuredText.HEADER;
71 import static org.nuiton.jrst.legacy.ReStructuredText.IMAGE;
72 import static org.nuiton.jrst.legacy.ReStructuredText.LABEL;
73 import static org.nuiton.jrst.legacy.ReStructuredText.LINE;
74 import static org.nuiton.jrst.legacy.ReStructuredText.LINE_BLOCK;
75 import static org.nuiton.jrst.legacy.ReStructuredText.LIST_ITEM;
76 import static org.nuiton.jrst.legacy.ReStructuredText.LITERAL;
77 import static org.nuiton.jrst.legacy.ReStructuredText.LITERAL_BLOCK;
78 import static org.nuiton.jrst.legacy.ReStructuredText.OPTION;
79 import static org.nuiton.jrst.legacy.ReStructuredText.OPTION_ARGUMENT;
80 import static org.nuiton.jrst.legacy.ReStructuredText.OPTION_GROUP;
81 import static org.nuiton.jrst.legacy.ReStructuredText.OPTION_LIST;
82 import static org.nuiton.jrst.legacy.ReStructuredText.OPTION_LIST_ITEM;
83 import static org.nuiton.jrst.legacy.ReStructuredText.OPTION_STRING;
84 import static org.nuiton.jrst.legacy.ReStructuredText.ORGANIZATION;
85 import static org.nuiton.jrst.legacy.ReStructuredText.PARAGRAPH;
86 import static org.nuiton.jrst.legacy.ReStructuredText.REFERENCE;
87 import static org.nuiton.jrst.legacy.ReStructuredText.REGEX_ANONYMOUS_HYPERLINK_REFERENCE;
88 import static org.nuiton.jrst.legacy.ReStructuredText.REGEX_EMAIL;
89 import static org.nuiton.jrst.legacy.ReStructuredText.REGEX_EMPHASIS;
90 import static org.nuiton.jrst.legacy.ReStructuredText.REGEX_FOOTNOTE_REFERENCE;
91 import static org.nuiton.jrst.legacy.ReStructuredText.REGEX_HYPERLINK_REFERENCE;
92 import static org.nuiton.jrst.legacy.ReStructuredText.REGEX_INLINE_REFERENCE;
93 import static org.nuiton.jrst.legacy.ReStructuredText.REGEX_LITERAL;
94 import static org.nuiton.jrst.legacy.ReStructuredText.REGEX_REFERENCE;
95 import static org.nuiton.jrst.legacy.ReStructuredText.REGEX_STRONG;
96 import static org.nuiton.jrst.legacy.ReStructuredText.REGEX_SUBSTITUTION_REFERENCE;
97 import static org.nuiton.jrst.legacy.ReStructuredText.REVISION;
98 import static org.nuiton.jrst.legacy.ReStructuredText.ROW;
99 import static org.nuiton.jrst.legacy.ReStructuredText.SECTION;
100 import static org.nuiton.jrst.legacy.ReStructuredText.SIDEBAR;
101 import static org.nuiton.jrst.legacy.ReStructuredText.STATUS;
102 import static org.nuiton.jrst.legacy.ReStructuredText.STRONG;
103 import static org.nuiton.jrst.legacy.ReStructuredText.SUBSTITUTION_DEFINITION;
104 import static org.nuiton.jrst.legacy.ReStructuredText.SUBTITLE;
105 import static org.nuiton.jrst.legacy.ReStructuredText.TABLE;
106 import static org.nuiton.jrst.legacy.ReStructuredText.TARGET;
107 import static org.nuiton.jrst.legacy.ReStructuredText.TBODY;
108 import static org.nuiton.jrst.legacy.ReStructuredText.TERM;
109 import static org.nuiton.jrst.legacy.ReStructuredText.TGROUP;
110 import static org.nuiton.jrst.legacy.ReStructuredText.THEAD;
111 import static org.nuiton.jrst.legacy.ReStructuredText.TITLE;
112 import static org.nuiton.jrst.legacy.ReStructuredText.TOPIC;
113 import static org.nuiton.jrst.legacy.ReStructuredText.TRANSITION;
114 import static org.nuiton.jrst.legacy.ReStructuredText.VERSION;
115
116
117 import java.io.BufferedReader;
118 import java.io.File;
119 import java.io.FileReader;
120 import java.io.IOException;
121 import java.io.InputStreamReader;
122 import java.io.Reader;
123 import java.io.StringReader;
124 import java.io.UnsupportedEncodingException;
125 import java.net.URL;
126 import java.net.URLEncoder;
127 import java.util.HashMap;
128 import java.util.LinkedList;
129 import java.util.List;
130 import java.util.Map;
131 import java.util.TreeSet;
132 import java.util.regex.Matcher;
133 import java.util.regex.Pattern;
134 import java.util.NoSuchElementException;
135
136 import org.apache.commons.lang.ObjectUtils;
137 import org.apache.commons.lang.StringEscapeUtils;
138 import org.apache.commons.logging.Log;
139 import org.apache.commons.logging.LogFactory;
140 import org.nuiton.jrst.JRSTDirective;
141 import org.nuiton.jrst.legacy.directive.ContentDirective;
142 import org.nuiton.jrst.legacy.directive.DateDirective;
143 import org.nuiton.jrst.legacy.directive.ImageDirective;
144 import org.nuiton.jrst.legacy.directive.SectnumDirective;
145 import org.nuiton.util.StringUtil;
146 import org.dom4j.Document;
147 import org.dom4j.DocumentException;
148 import org.dom4j.DocumentHelper;
149 import org.dom4j.Element;
150 import org.dom4j.IllegalAddException;
151 import org.dom4j.Node;
152 import org.dom4j.VisitorSupport;
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362 public class JRSTReader {
363
364
365 private static Log log = LogFactory.getLog(JRSTReader.class);
366
367 protected static final String ANONYMOUS = "anonymous";
368
369 protected static final String AUTO = "auto";
370
371 protected static final String AUTONUM = "autoNum";
372
373 protected static final String AUTONUMLABEL = "autoNumLabel";
374
375 protected static final String AUTOSYMBOL = "autoSymbol";
376
377 protected static final String ATTR_REFID = "refid";
378
379 protected static final String ATTR_INLINE = "inline";
380
381 protected static final String ATTR_IDS = "ids";
382
383 protected static final String BACKREFS = "backrefs";
384
385 protected static final String BULLET = "bullet";
386
387 protected static final String CLASS = "class";
388
389 protected static final String CONTENTS = "contents";
390
391 protected static final String DELIMITER = "delimiter";
392
393 protected static final String DELIMITEREXISTE ="delimiterExiste";
394
395 protected static final String ENUMTYPE = "enumtype";
396
397 protected static final String FOOTNOTES = "footnotes";
398
399 protected static final String ID = "id";
400
401 protected static final String INCLUDE = "include";
402
403 protected static final String LEVEL = "level";
404
405 protected static final String NAME = "name";
406
407 protected static final String NAMES = "names";
408
409 protected static final String NUM = "num";
410
411 protected static final String REFURI = "refuri";
412
413 protected static final String PREFIX = "prefix";
414
415 protected static final String REMOVE = "remove";
416
417 protected static final String START = "start";
418
419 protected static final String SECTNUM = "sectnum";
420
421 protected static final String SUBEXISTE = "subExiste";
422
423 protected static final String SUFFIX = "suffix";
424
425 protected static final String TRUE = "true";
426
427 protected static final String TYPE = "type";
428
429 protected static final String TARGETANONYMOUS = "targetAnonymous";
430
431 protected static final String VALUE = "value";
432
433 protected boolean ERROR_MISSING_ITEM;
434
435 protected static int MAX_SECTION_DEPTH = -1000;
436
437 protected static Map<String, JRSTDirective> defaultDirectives;
438
439 protected Map<String, JRSTDirective> directives = new HashMap<String, JRSTDirective>();
440
441 private boolean sectnum;
442
443 private Element footer;
444
445 private int idMax;
446
447 private int symbolMax;
448
449 private int symbolMaxRef;
450
451 private LinkedList<Integer> lblFootnotes = new LinkedList<Integer>();
452
453 private LinkedList<Integer> lblFootnotesRef = new LinkedList<Integer>();
454
455 private LinkedList<Element> eFootnotes = new LinkedList<Element>();
456
457 private LinkedList<Element> eTarget = new LinkedList<Element>();
458
459 private LinkedList<Element> eTargetAnonymous = new LinkedList<Element>();
460
461 private LinkedList<Element> eTargetAnonymousCopy = new LinkedList<Element>();
462
463 private LinkedList<Element> eTitle = new LinkedList<Element>();
464
465 static {
466 defaultDirectives = new HashMap<String, JRSTDirective>();
467 defaultDirectives.put(IMAGE, new ImageDirective());
468 defaultDirectives.put(DATE, new DateDirective());
469 defaultDirectives.put("time", new DateDirective());
470 defaultDirectives.put(CONTENTS, new ContentDirective());
471
472 defaultDirectives.put(SECTNUM, new SectnumDirective());
473
474 }
475
476
477
478
479 public JRSTReader() {
480 }
481
482
483
484
485
486 public static JRSTDirective getDefaultDirective(String name) {
487 return defaultDirectives.get(name);
488 }
489
490
491
492
493
494 public static void addDefaultDirectives(String name, JRSTDirective directive) {
495 JRSTReader.defaultDirectives.put(name, directive);
496 }
497
498
499
500
501
502 public JRSTDirective getDirective(String name) {
503 return directives.get(name);
504 }
505
506
507
508
509
510 public void addDirectives(String name, JRSTDirective directive) {
511 directives.put(name, directive);
512 }
513
514
515
516
517
518
519
520
521
522 public Document read(Reader reader) throws Exception {
523 JRSTLexer lexer = new JRSTLexer(reader);
524 try {
525 Element root = composeDocument(lexer);
526
527 Document result = DocumentHelper.createDocument();
528 result.setRootElement(root);
529
530 root.accept(new VisitorSupport() {
531 @Override
532 public void visit(Element e) {
533
534 e.addAttribute(LEVEL, null);
535
536 String type = e.attributeValue(TYPE);
537 if (type != null) {
538 if (type.equals(CONTENTS)) {
539 composeContents(e);
540 e.addAttribute(TYPE, null);
541 }
542 }
543
544 if (TRUE.equalsIgnoreCase(e.attributeValue(ATTR_INLINE))) {
545 e.addAttribute(ATTR_INLINE, null);
546 try {
547 inline(e);
548 } catch (DocumentException eee) {
549 if (log.isWarnEnabled()) {
550 log.warn("Can't inline text for " + e, eee);
551 }
552 } catch (UnsupportedEncodingException ee) {
553 if (log.isWarnEnabled()) {
554 log.warn("Unsupported encoding " + e, ee);
555 }
556 }
557 }
558 }
559 });
560
561 return result;
562 } catch (Exception eee) {
563 log.error(t("JRST parsing error line %d char %s:\n%s", lexer
564 .getLineNumber(), lexer.getCharNumber(), lexer
565 .readNotBlanckLine()));
566 throw eee;
567 }
568 }
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587 private void composeContents(Element e) {
588 Element result = DocumentHelper.createElement(TOPIC);
589 String option = e.getText();
590 int depth = -1;
591
592 Pattern pattern = Pattern.compile("\\s*\\:depth\\:\\s*\\p{Digit}+");
593 Matcher matcher = pattern.matcher(option);
594 if (matcher.matches()) {
595 pattern = Pattern.compile("\\p{Digit}+");
596 matcher = pattern.matcher(matcher.group());
597 if (matcher.find()) {
598 depth = Integer.parseInt(matcher.group());
599 }
600 }
601 int levelInit = 0;
602 boolean noTitle = false;
603
604 try {
605 levelInit = Integer.parseInt(eTitle.getFirst().attributeValue(
606 LEVEL));
607 } catch (NumberFormatException eee) {
608 log.error("Can't parse level in: "
609 + eTitle.getFirst().asXML(), eee);
610 return;
611 } catch (NoSuchElementException eee) {
612 noTitle = true;
613 }
614
615 LinkedList<Element> title = new LinkedList<Element>();
616
617 for (int i = 0; i < eTitle.size(); i++) {
618 idMax++;
619 eTitle.get(i).addAttribute(ATTR_REFID, ID + idMax);
620 }
621
622 for (Element el : eTitle) {
623 int level = Integer.parseInt(el.attributeValue(LEVEL));
624 level = level - levelInit;
625 el.addAttribute(LEVEL, "" + level);
626 if (depth == -1) {
627 title.add(el);
628 }
629 else {
630 if (depth > level) {
631 title.add(el);
632 }
633 }
634 }
635 e.addAttribute(CLASS, CONTENTS);
636 String titleValue = e.attributeValue(VALUE);
637 e.addAttribute(VALUE, null);
638 String value = titleValue.trim().toLowerCase();
639
640 if (value.matches("\\s*")) {
641 value = CONTENTS;
642 titleValue = "Contents";
643 }
644 e.addAttribute(ATTR_IDS, value);
645 e.addAttribute(NAMES, value);
646 result.addElement(TITLE).setText(titleValue);
647
648 if (!noTitle) {
649 result.add(composeLineContent(title, ""));
650 }
651 e.setText("");
652 e.appendContent(result);
653 }
654
655
656
657
658
659
660 private Element composeLineContent(LinkedList<Element> title, String num) {
661 Element result = DocumentHelper.createElement(BULLET_LIST);
662 if (sectnum) {
663 result.addAttribute(CLASS, "auto-toc");
664 }
665 Element item = null;
666 int cnt = 0;
667 while (!title.isEmpty()) {
668
669 Element e = title.getFirst();
670 int level = Integer.parseInt(e.attributeValue(LEVEL));
671 LinkedList<Element> child = new LinkedList<Element>();
672
673 if (level <= 0) {
674 cnt++;
675 title.removeFirst();
676 item = result.addElement(LIST_ITEM);
677 Element para = item.addElement(PARAGRAPH);
678 Element reference = para.addElement(REFERENCE);
679 String text = e.getText();
680 String id = e.attributeValue(ATTR_REFID);
681 reference.addAttribute(ATTR_IDS, id);
682 reference.addAttribute(ATTR_REFID, text.replaceAll("\\W+", " ")
683 .trim().toLowerCase().replaceAll("\\W+", "-"));
684
685 if (sectnum) {
686 Element generated = reference.addElement(GENERATED)
687 .addAttribute(CLASS, SECTNUM);
688 generated.setText(num + cnt + " ");
689 for (int i = 0; i < eTitle.size(); i++) {
690 if (eTitle.get(i).attributeValue(ATTR_REFID).equals(id)) {
691 Element generatedTitle = eTitle.get(i).addElement(
692 GENERATED);
693 generatedTitle.addAttribute(CLASS, SECTNUM);
694 generatedTitle.setText(num + cnt + " ");
695 }
696
697 }
698 }
699
700 text = text.trim();
701 text = text.replaceAll("_", "");
702
703 text = REGEX_STRONG.matcher(text).replaceAll(
704 "<" + STRONG + ">$1</" + STRONG + ">");
705 text = REGEX_EMPHASIS.matcher(text).replaceAll(
706 "<" + EMPHASIS + ">$1</" + EMPHASIS + ">");
707
708 try {
709 Element textElement = DocumentHelper.parseText("<TMP>" + text + "</TMP>").getRootElement();
710 reference.appendContent(textElement);
711
712 } catch (DocumentException eee) {
713 if (log.isWarnEnabled()) {
714 log.warn("Can't inline text for " + e, eee);
715 }
716 }
717
718 } else {
719 do {
720 e.addAttribute(LEVEL, "" + (level - 1));
721 child.add(e);
722 title.removeFirst();
723 if (!title.isEmpty()) {
724 e = title.getFirst();
725 level = Integer.parseInt(e.attributeValue(LEVEL));
726 }
727 } while (!title.isEmpty() && level > 0);
728 String numTmp = "";
729
730 if (sectnum) {
731 numTmp = num + cnt + ".";
732 }
733 if (item != null) {
734 item.add(composeLineContent(child, numTmp));
735
736 } else {
737 result.add(composeLineContent(child, numTmp));
738
739 }
740 }
741 }
742 return result;
743 }
744
745
746
747
748
749
750 private Element composeDocument(JRSTLexer lexer) throws Exception {
751 Element result = DocumentHelper.createElement(DOCUMENT);
752 result.addAttribute(LEVEL, String.valueOf(MAX_SECTION_DEPTH - 1));
753
754 Element item = null;
755
756
757 skipBlankLine(lexer);
758
759
760 LinkedList<Element> items = lexer.refTarget();
761 for (Element e : items) {
762 eTarget.add(e);
763
764 }
765
766
767 item = lexer.peekHeader();
768 if (itemEquals(HEADER, item)) {
769 Element decoration = result.addElement(DECORATION);
770 Element header = decoration.addElement(HEADER);
771 header.addAttribute(ATTR_INLINE, TRUE).setText(item.getText());
772 }
773
774
775 item = lexer.peekFooter();
776 if (itemEquals(FOOTER, item)) {
777 footer = DocumentHelper.createElement(DECORATION);
778 Element header = footer.addElement(FOOTER);
779 header.addAttribute(ATTR_INLINE, TRUE).setText(item.getText());
780 }
781
782
783 LinkedList<Element> listItem = lexer.peekTargetAnonymous();
784 if (listItem != null) {
785 for (Element e : listItem) {
786 Element anonym = DocumentHelper.createElement(TARGET);
787 anonym.addAttribute(ANONYMOUS, "1");
788 idMax++;
789 anonym.addAttribute(ATTR_IDS, ID + idMax);
790
791 anonym.addAttribute(REFURI, e.attributeValue(REFURI).trim());
792
793 eTargetAnonymous.add(anonym);
794 eTargetAnonymousCopy.add(anonym);
795 }
796 }
797
798
799 item = lexer.peekRemove();
800 if (itemEquals(REMOVE, item)) {
801 lexer.remove();
802 }
803
804
805 skipBlankLine(lexer);
806
807
808 List<Element> comments = lexer.peekAllComment();
809
810
811 skipBlankLine(lexer);
812
813
814 item = lexer.peekTitle();
815 if (itemEquals(TITLE, item)) {
816 lexer.remove();
817 Element title = result.addElement(TITLE);
818 String txt = item.getText();
819 result.addAttribute(ATTR_IDS, txt.replaceAll("[(\\W+)_]", " ")
820 .toLowerCase().trim().replaceAll("\\s+", "-"));
821 result.addAttribute(NAMES, txt.toLowerCase().replaceAll(
822 "[(\\W+)_&&[^\\:]]+", " ").trim());
823 copyLevel(item, title);
824 title.addAttribute(ATTR_INLINE, TRUE).setText(txt.trim());
825 }
826
827
828 skipBlankLine(lexer);
829
830
831 item = lexer.peekTitle();
832 if (itemEquals(TITLE, item)) {
833 lexer.remove();
834 Element subtitle = result.addElement(SUBTITLE);
835 String txt = item.getText();
836 subtitle.addAttribute(ATTR_IDS, txt.replaceAll("[(\\W+)_]", " ")
837 .toLowerCase().trim().replaceAll("\\s+", "-"));
838 subtitle.addAttribute(NAMES, txt.toLowerCase().replaceAll(
839 "[(\\W+)_]", " ").trim());
840 copyLevel(item, subtitle);
841 DocumentHelper.createElement(FOOTNOTES);
842 subtitle.addAttribute(ATTR_INLINE, TRUE).setText(txt.trim());
843 }
844
845
846 skipBlankLine(lexer);
847
848
849 item = lexer.peekDocInfo();
850 Element documentinfo = null;
851 while (itemEquals(DOCINFO, item) || itemEquals(FIELD_LIST, item)) {
852
853 if (documentinfo == null) {
854 documentinfo = result.addElement(DOCINFO);
855 }
856 skipBlankLine(lexer);
857 if (itemEquals(FIELD_LIST, item)) {
858 Element field = composeFieldItemList(lexer);
859 documentinfo.add(field);
860 } else {
861 if ("author".equalsIgnoreCase(item.attributeValue(TYPE))) {
862 documentinfo.addElement(AUTHOR).addAttribute(ATTR_INLINE,
863 TRUE).setText(item.getText());
864 } else if ("date".equalsIgnoreCase(item.attributeValue(TYPE))) {
865 documentinfo.addElement(DATE)
866 .addAttribute(ATTR_INLINE, TRUE).setText(
867 item.getText().trim());
868 } else if ("organization".equalsIgnoreCase(item
869 .attributeValue(TYPE))) {
870 documentinfo.addElement(ORGANIZATION).addAttribute(
871 ATTR_INLINE, TRUE).setText(item.getText().trim());
872 } else if ("contact".equalsIgnoreCase(item
873 .attributeValue(TYPE))) {
874 documentinfo.addElement(CONTACT).addAttribute(ATTR_INLINE,
875 TRUE).setText(item.getText().trim());
876 } else if ("address".equalsIgnoreCase(item
877 .attributeValue(TYPE))) {
878 documentinfo.addElement(ADDRESS).addAttribute(ATTR_INLINE,
879 TRUE).setText(item.getText().trim());
880 } else if ("version".equalsIgnoreCase(item
881 .attributeValue(TYPE))) {
882 documentinfo.addElement(VERSION).addAttribute(ATTR_INLINE,
883 TRUE).setText(item.getText().trim());
884 } else if ("revision".equalsIgnoreCase(item
885 .attributeValue(TYPE))) {
886 documentinfo.addElement(REVISION).addAttribute(ATTR_INLINE,
887 TRUE).setText(item.getText().trim());
888 } else if ("status".equalsIgnoreCase(item
889 .attributeValue(TYPE))) {
890 documentinfo.addElement(STATUS).addAttribute(ATTR_INLINE,
891 TRUE).setText(item.getText().trim());
892 } else if ("copyright".equalsIgnoreCase(item
893 .attributeValue(TYPE))) {
894 documentinfo.addElement(COPYRIGHT).addAttribute(ATTR_INLINE,
895 TRUE).setText(item.getText().trim());
896 } else if ("authors".equalsIgnoreCase(item
897 .attributeValue(TYPE))) {
898 Element authors = documentinfo.addElement(AUTHORS);
899 int t = 0;
900 String line = item.getText();
901 for (int i = 0; i < line.length(); i++) {
902 if (line.charAt(i) == ';' || line.charAt(i) == ',') {
903 authors.addElement(AUTHOR).addAttribute(ATTR_INLINE,
904 TRUE)
905 .setText(line.substring(t, i).trim());
906 t = i + 1;
907 }
908
909 }
910 authors.addElement(AUTHOR).addAttribute(ATTR_INLINE, TRUE)
911 .setText(line.substring(t, line.length()).trim());
912 }
913 lexer.remove();
914 }
915
916
917 item = lexer.peekDocInfo();
918
919 }
920
921
922
923 for (Element comment : comments){
924 result.add(composeComment(comment));
925 }
926
927
928 item = lexer.peekTitle();
929 while (itemNotEquals(TITLE, item) && !lexer.eof()) {
930 composeBody(lexer, result);
931 item = lexer.peekTitle();
932 }
933
934
935 item = lexer.peekTitle();
936 while (itemEquals(TITLE, item, true, lexer.eof())) {
937 Element section = composeSection(lexer);
938 result.add(section);
939 item = lexer.peekTitle();
940 }
941
942
943 if (footer != null) {
944 result.add(footer);
945 }
946
947 return result;
948 }
949
950
951
952
953
954
955
956
957
958
959 private void skipBlankLine(JRSTLexer lexer) throws IOException,
960 DocumentException {
961 Element item = lexer.peekBlankLine();
962
963 while (itemEquals(JRSTLexer.BLANK_LINE, item)) {
964
965 lexer.remove();
966 item = lexer.peekBlankLine();
967 }
968 }
969
970
971
972
973
974
975
976
977
978
979
980
981 private Element composeBody(JRSTLexer lexer, Element parent)
982 throws Exception {
983
984 Element item = lexer.peekTitleOrBodyElement();
985 if (item == null && !lexer.eof()) {
986 item = lexer.peekTitleOrBodyElement();
987 }
988
989 while (!lexer.eof() && itemNotEquals(TITLE, item)
990 && isUpperLevel(item, parent)) {
991 if (itemEquals(JRSTLexer.BLANK_LINE, item)) {
992
993 lexer.remove();
994 } else if (itemEquals(REMOVE, item)) {
995 lexer.remove();
996 } else if (itemEquals(INCLUDE, item)) {
997 lexer.remove();
998 Element list = composeInclude(item);
999 parent.add(list);
1000 } else if (itemEquals(DOCTEST_BLOCK, item)) {
1001 lexer.remove();
1002 Element list = composeDoctestBlock(item);
1003 parent.add(list);
1004 } else if (itemEquals(ADMONITION, item)) {
1005 lexer.remove();
1006 Element list = composeAdmonition(item);
1007 parent.add(list);
1008 } else if (itemEquals(SIDEBAR, item)) {
1009 lexer.remove();
1010 Element list = composeSidebar(item);
1011 parent.add(list);
1012 } else if (itemEquals(TOPIC, item)) {
1013 lexer.remove();
1014 Element list = composeTopic(item);
1015 parent.add(list);
1016 } else if (itemEquals(TRANSITION, item)) {
1017 lexer.remove();
1018 Element para = parent.addElement(TRANSITION);
1019 copyLevel(item, para);
1020 } else if (itemEquals(PARAGRAPH, item)) {
1021 lexer.remove();
1022 Element para = parent.addElement(PARAGRAPH);
1023 copyLevel(item, para);
1024 para.addAttribute(ATTR_INLINE, TRUE).setText(item.getText());
1025 } else if (itemEquals(JRSTLexer.DIRECTIVE, item)) {
1026 lexer.remove();
1027 Node directive = composeDirective(item);
1028 parent.add(directive);
1029 } else if (itemEquals(SUBSTITUTION_DEFINITION, item)) {
1030 lexer.remove();
1031 Element subst = composeSubstitutionDefinition(item);
1032 parent.add(subst);
1033 } else if (itemEquals(LITERAL_BLOCK, item)) {
1034 lexer.remove();
1035 Element para = parent.addElement(LITERAL_BLOCK);
1036 copyLevel(item, para);
1037 para.setText(item.getText());
1038 } else if (itemEquals(JRSTLexer.TABLE, item)) {
1039 lexer.remove();
1040 Element table = composeTable(item);
1041 parent.add(table);
1042
1043
1044
1045 } else if (itemEquals(LINE_BLOCK, item)) {
1046 lexer.remove();
1047 Element list = composeLineBlock(lexer, item);
1048 parent.add(list);
1049 } else if (itemEquals(BULLET_LIST, item)) {
1050 Element list = composeBulletList(lexer);
1051 parent.add(list);
1052 } else if (itemEquals(ENUMERATED_LIST, item)) {
1053 Element list = composeEnumeratedList(lexer);
1054 parent.add(list);
1055 } else if (itemEquals(DEFINITION_LIST, item)) {
1056 Element list = composeDefinitionList(lexer);
1057 parent.add(list);
1058 } else if (itemEquals(FIELD_LIST, item)) {
1059 Element list = composeFieldList(lexer);
1060 parent.add(list);
1061 } else if (itemEquals(BLOCK_QUOTE, item)) {
1062 lexer.remove();
1063 Element list = composeBlockQuote(item);
1064 parent.add(list);
1065 } else if (itemEquals(OPTION_LIST, item)) {
1066 Element list = composeOptionList(lexer);
1067 parent.add(list);
1068 } else if (itemEquals(TARGET, item)) {
1069 lexer.remove();
1070 Element list = composeTarget(item);
1071 if (list != null) {
1072 try {
1073 parent.add(list);
1074 } catch (IllegalAddException e) {}
1075 } else
1076 System.err.println("Unknown target name : \"" + item.attributeValue(ATTR_IDS) + "\"");
1077 } else if (itemEquals(TARGETANONYMOUS, item)) {
1078 lexer.remove();
1079 Element list = composeTargetAnonymous(item);
1080 parent.add(list);
1081 } else if (itemEquals(FOOTNOTES, item)) {
1082 lexer.remove();
1083 Element[] list = composeFootnote(item);
1084 for (Element l : list) {
1085 parent.add(l);
1086 }
1087 } else if (itemEquals(COMMENT, item)) {
1088 lexer.remove();
1089 Element list = composeComment(item);
1090 parent.add(list);
1091 }
1092
1093 else {
1094 if (ERROR_MISSING_ITEM) {
1095 throw new DocumentException("Unknow item type: "
1096 + item.getName());
1097 } else {
1098 lexer.remove();
1099 }
1100 }
1101
1102
1103
1104
1105 item = lexer.peekTitleOrBodyElement();
1106 }
1107
1108 return parent;
1109 }
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133 private Element composeInclude(Element item) throws Exception {
1134 String option = item.attributeValue(OPTION);
1135 String path = item.getText();
1136 Element result = null;
1137 if (option.equals(LITERAL)) {
1138 result = DocumentHelper.createElement(LITERAL_BLOCK);
1139 FileReader reader = new FileReader(path);
1140 BufferedReader bf = new BufferedReader(reader);
1141 String line = "";
1142 String lineTmp = bf.readLine();
1143 while (lineTmp != null) {
1144 line += '\n' + lineTmp;
1145 lineTmp = bf.readLine();
1146 }
1147 result.setText(line);
1148 } else {
1149 File fileIn = new File(path);
1150 URL url = fileIn.toURI().toURL();
1151 Reader in = new InputStreamReader(url.openStream());
1152
1153 Document doc = newJRSTReader(in);
1154
1155 result = doc.getRootElement();
1156 }
1157 return result;
1158 }
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170 private Element composeComment(Element item) {
1171
1172 return item;
1173 }
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183 private Element composeTargetAnonymous(Element item) {
1184 Element result = null;
1185 result = eTargetAnonymousCopy.getFirst();
1186 eTargetAnonymousCopy.removeFirst();
1187 return result;
1188 }
1189
1190
1191
1192
1193
1194
1195
1196 private Element composeTarget(Element item) {
1197 Element result = null;
1198 for (Element e : eTarget) {
1199 if (e.attributeValue(ID).equals(item.attributeValue(ID))) {
1200 result = e;
1201 }
1202 }
1203 return result;
1204 }
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215 private Element[] composeFootnote(Element item) throws Exception {
1216 Element[] result = null;
1217 if (itemEquals(FOOTNOTES, item)) {
1218 List<Element> footnotes = (List<Element>) item
1219 .selectNodes(FOOTNOTE);
1220 result = new Element[footnotes.size()];
1221 int cnt = 0;
1222 for (Element footnote : footnotes) {
1223 result[cnt] = DocumentHelper.createElement(FOOTNOTE);
1224 Element efootnote = DocumentHelper.createElement(FOOTNOTE);
1225 int labelMax = 0;
1226
1227 for (int i = 0; i < lblFootnotes.size(); i++) {
1228 int lbl = lblFootnotes.get(i);
1229 labelMax = Math.max(lbl, labelMax);
1230 }
1231
1232 boolean[] labels = new boolean[labelMax];
1233 for (int i = 0; i < labels.length; i++) {
1234 labels[i] = false;
1235 }
1236 for (int i = 0; i < lblFootnotes.size(); i++) {
1237 labels[lblFootnotes.get(i) - 1] = true;
1238 }
1239 idMax++;
1240 String name = null;
1241 String id = "";
1242 String label = null;
1243 String type = footnote.attributeValue(TYPE);
1244 if (type.equals(AUTONUM) || type.equals(AUTONUMLABEL)) {
1245 result[cnt].addAttribute(AUTO, "1");
1246 }
1247 if (type.equals(AUTOSYMBOL)) {
1248 result[cnt].addAttribute(AUTO, "*");
1249 }
1250 result[cnt].addAttribute(BACKREFS, ID + idMax);
1251 efootnote.addAttribute(BACKREFS, ID + idMax);
1252 if (type.equals(NUM) || type.equals(AUTONUMLABEL)) {
1253 name = footnote.attributeValue(NAME);
1254 if (type.equals(AUTONUMLABEL)) {
1255 id = name;
1256 }
1257 else {
1258 label = name;
1259 }
1260 }
1261 if (type.equals(AUTONUM) || type.equals(AUTONUMLABEL)) {
1262 boolean done = false;
1263
1264 for (int i = 0; i < labels.length && !done; i++) {
1265 if (!labels[i]) {
1266 done = true;
1267 label = "" + (i + 1);
1268 }
1269 }
1270 if (!done) {
1271 label = "" + (labels.length + 1);
1272 }
1273 if (type.equals(AUTONUM)) {
1274 name = label;
1275 }
1276 }
1277 if (type.equals(AUTOSYMBOL)) {
1278
1279 int nb = Math.abs(symbolMax / 10) + 1;
1280 char symbol = FOOTNOTE_SYMBOL.charAt(symbolMax % 10);
1281 label = "";
1282 for (int j = 0; j < nb; j++) {
1283 label += symbol;
1284 }
1285 symbolMax++;
1286
1287 }
1288 result[cnt].addAttribute(ATTR_IDS, "" + id);
1289 efootnote.addAttribute(ATTR_IDS, "" + id);
1290 if (!type.equals(AUTOSYMBOL)) {
1291 result[cnt].addAttribute(NAME, "" + name);
1292 efootnote.addAttribute(NAME, "" + name);
1293 }
1294 result[cnt].addElement(LABEL).setText("" + label);
1295 efootnote.addAttribute(LABEL, "" + label);
1296 if (!type.equals(AUTOSYMBOL)) {
1297 lblFootnotes.add(Integer.parseInt(label));
1298 }
1299 efootnote.addAttribute(TYPE, type);
1300 eFootnotes.add(efootnote);
1301 String text = footnote.getText();
1302 Document doc = newJRSTReader(new StringReader(text));
1303 result[cnt].appendContent(doc.getRootElement());
1304
1305 cnt++;
1306 }
1307 }
1308 for (int i = 0; i < result.length; i++) {
1309 if (result[i].attributeValue(ATTR_IDS).equals("")) {
1310 idMax++;
1311 result[i].addAttribute(ATTR_IDS, ID + idMax);
1312 (eFootnotes.get(i)).addAttribute(ATTR_IDS, ID + idMax);
1313 }
1314
1315 }
1316
1317 return result;
1318 }
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331 private Element composeOptionList(JRSTLexer lexer)
1332 throws DocumentException, Exception {
1333 Element item = lexer.peekOption();
1334 Element result = DocumentHelper.createElement(OPTION_LIST);
1335 while (itemEquals(OPTION_LIST, item)) {
1336 lexer.remove();
1337 Element optionListItem = result.addElement(OPTION_LIST_ITEM);
1338 Element optionGroup = optionListItem.addElement(OPTION_GROUP);
1339 List<Element> option = (List<Element>) item.selectNodes(OPTION);
1340 for (Element e : option) {
1341 Element eOption = optionGroup.addElement(OPTION);
1342 eOption.addElement(OPTION_STRING).setText(
1343 e.attributeValue(OPTION_STRING));
1344 if (e.attributeValue(DELIMITEREXISTE).equals(TRUE)) {
1345 eOption.addElement(OPTION_ARGUMENT).addAttribute(
1346 DELIMITER, e.attributeValue(DELIMITER))
1347 .setText(e.attributeValue(OPTION_ARGUMENT));
1348 }
1349 }
1350 Element description = optionListItem.addElement(DESCRIPTION);
1351
1352 String text = item.getText();
1353 Document doc = newJRSTReader(new StringReader(text));
1354 description.appendContent(doc.getRootElement());
1355
1356 item = lexer.peekOption();
1357 }
1358 return result;
1359 }
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374 private Element composeTopic(Element item) throws Exception {
1375 Element result = null;
1376 result = DocumentHelper.createElement(TOPIC);
1377 result.addElement(TITLE).addAttribute(ATTR_INLINE, TRUE).setText(
1378 item.attributeValue(TITLE));
1379 String text = item.getText();
1380 Document doc = newJRSTReader(new StringReader(text));
1381 result.appendContent(doc.getRootElement());
1382
1383 return result;
1384 }
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399 private Element composeSidebar(Element item) throws Exception {
1400 Element result = null;
1401 result = DocumentHelper.createElement(SIDEBAR);
1402 result.addElement(TITLE).addAttribute(ATTR_INLINE, TRUE).setText(
1403 item.attributeValue(TITLE));
1404 if (item.attributeValue(SUBEXISTE).equals(TRUE)) {
1405 result.addElement(SUBTITLE).addAttribute(ATTR_INLINE, TRUE).setText(
1406 item.attributeValue(SUBTITLE));
1407 }
1408
1409 String text = item.getText();
1410 Document doc = newJRSTReader(new StringReader(text));
1411 result.appendContent(doc.getRootElement());
1412
1413 return result;
1414 }
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428 private Element composeLineBlock(JRSTLexer lexer, Element item)
1429 throws Exception {
1430 Element result = null;
1431 result = DocumentHelper.createElement(LINE_BLOCK);
1432 List<Element> lines = (List<Element>) item.selectNodes(LINE);
1433 int[] levels = new int[lines.size()];
1434 int cnt = 0;
1435 for (Element l : lines) {
1436 levels[cnt] = Integer.parseInt(l.attributeValue(LEVEL));
1437 cnt++;
1438 }
1439 cnt = 0;
1440 boolean[] lineDone = new boolean[lines.size()];
1441 for (int i = 0; i < lineDone.length; i++) {
1442 lineDone[i] = false;
1443 }
1444 for (Element l : lines) {
1445 if (levels[cnt] == 0) {
1446 result.addElement(LINE).addAttribute(ATTR_INLINE, TRUE).setText(
1447 l.getText());
1448 }
1449 else {
1450 if (!lineDone[cnt]) {
1451 Element newItem = DocumentHelper.createElement(LINE_BLOCK);
1452 Boolean done = false;
1453 for (int i = cnt; i < lines.size() && !done; i++) {
1454 if (levels[i] > 0) {
1455 Element eLine = newItem.addElement(LINE);
1456 eLine.addAttribute(LEVEL, "" + (levels[i] - 1));
1457 eLine.setText(lines.get(i).getText());
1458 lineDone[i] = true;
1459 } else {
1460 done = true;
1461 }
1462
1463 }
1464 Element eLineBlock = result.addElement(LINE_BLOCK);
1465
1466 eLineBlock.appendContent(composeLineBlock(lexer, newItem));
1467 }
1468 }
1469 cnt++;
1470
1471 }
1472 return result;
1473 }
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484 private Element composeDoctestBlock(Element item) {
1485 return item;
1486 }
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502 private Element composeBlockQuote(Element item) throws Exception {
1503 Element result = null;
1504 result = DocumentHelper.createElement(BLOCK_QUOTE);
1505
1506 String text = item.getText();
1507 Document doc = newJRSTReader(new StringReader(text));
1508 result.appendContent(doc.getRootElement());
1509 String sAttribution = item.attributeValue(ATTRIBUTION);
1510 if (sAttribution != null) {
1511 Element attribution = result.addElement(ATTRIBUTION);
1512 attribution.setText(sAttribution);
1513 attribution.addAttribute(ATTR_INLINE, TRUE);
1514 }
1515 return result;
1516 }
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530 private Element composeAdmonition(Element item) throws Exception {
1531 Element result = null;
1532 if (item.attributeValue(TYPE).equalsIgnoreCase(ADMONITION)) {
1533 result = DocumentHelper.createElement(ADMONITION);
1534 String title = item.attributeValue(TITLE);
1535 String admonitionClass = "admonition_" + title;
1536 admonitionClass = admonitionClass.toLowerCase().replaceAll(
1537 "\\p{Punct}", "");
1538 admonitionClass = admonitionClass.replace(' ', '-');
1539 admonitionClass = admonitionClass.replace('\n', '-');
1540 result.addAttribute(CLASS, admonitionClass);
1541 result.addElement(TITLE).addAttribute(ATTR_INLINE, TRUE).setText(
1542 title.trim());
1543 } else {
1544 result = DocumentHelper.createElement(item.attributeValue(TYPE)
1545 .toLowerCase());
1546 }
1547
1548 String text = item.getText();
1549 Document doc = newJRSTReader(new StringReader(text));
1550 result.appendContent(doc.getRootElement());
1551 return result;
1552 }
1553
1554
1555
1556
1557
1558
1559
1560 private Node composeDirective(Element item) {
1561 Node result = item;
1562 String type = item.attributeValue(JRSTLexer.DIRECTIVE_TYPE);
1563 if (type.equals(SECTNUM)) {
1564 sectnum = true;
1565 }
1566 JRSTDirective directive = getDirective(type);
1567 if (directive == null) {
1568 directive = getDefaultDirective(type);
1569 }
1570 if (directive != null) {
1571 result = directive.parse(item);
1572 } else {
1573 log.warn("Unknow directive type '" + type + "' in: " + item);
1574 }
1575 return result;
1576 }
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586 private Element composeSubstitutionDefinition(Element item) {
1587 Element result = item;
1588 Element child = (Element) item.selectSingleNode("*");
1589 Node newChild = composeDirective(child);
1590 result.remove(child);
1591
1592 result.add(newChild);
1593 return result;
1594 }
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627 private Element composeTable(Element item) throws Exception {
1628
1629 Element result = DocumentHelper.createElement(TABLE);
1630
1631 int tableWidth = Integer.parseInt(item
1632 .attributeValue(JRSTLexer.TABLE_WIDTH));
1633
1634 TreeSet<Integer> beginCellList = new TreeSet<Integer>();
1635
1636 for (Element cell : (List<Element>) item.selectNodes(JRSTLexer.ROW
1637 + "/" + JRSTLexer.CELL)) {
1638 Integer begin = Integer.valueOf(cell
1639 .attributeValue(JRSTLexer.CELL_INDEX_START));
1640 beginCellList.add(begin);
1641 }
1642
1643 int[] beginCell = new int[beginCellList.size() + 1];
1644
1645
1646
1647 int[] lengthCell = new int[beginCellList.size()];
1648
1649 int cellNumber = 0;
1650 for (int b : beginCellList) {
1651 beginCell[cellNumber] = b;
1652 if (cellNumber > 0) {
1653 lengthCell[cellNumber - 1] = beginCell[cellNumber]
1654 - beginCell[cellNumber - 1];
1655 }
1656 cellNumber++;
1657 }
1658 beginCell[cellNumber] = tableWidth;
1659 lengthCell[cellNumber - 1] = beginCell[cellNumber]
1660 - beginCell[cellNumber - 1];
1661
1662 Element tgroup = result.addElement(TGROUP).addAttribute("cols",
1663 String.valueOf(cellNumber));
1664 for (int width : lengthCell) {
1665 tgroup.addElement(COLSPEC).addAttribute("colwidth",
1666 String.valueOf(width));
1667 }
1668
1669 Element rowList = null;
1670 if (TRUE.equals(item.attributeValue(JRSTLexer.TABLE_HEADER))) {
1671 rowList = tgroup.addElement(THEAD);
1672 } else {
1673 rowList = tgroup.addElement(TBODY);
1674 }
1675 List<Element> rows = (List<Element>) item.selectNodes(JRSTLexer.ROW);
1676 for (int r = 0; r < rows.size(); r++) {
1677 Element row = rowList.addElement(ROW);
1678 List<Element> cells = (List<Element>) rows.get(r).selectNodes(
1679 JRSTLexer.CELL);
1680 for (int c = 0; c < cells.size(); c++) {
1681 Element cell = cells.get(c);
1682
1683
1684 if (!TRUE.equals(cell.attributeValue("used"))) {
1685 Element entry = row.addElement(ENTRY);
1686 String text = "";
1687
1688
1689 int morerows = -1;
1690 Element tmpCell = null;
1691 String cellStart = cell
1692 .attributeValue(JRSTLexer.CELL_INDEX_START);
1693 do {
1694 morerows++;
1695 tmpCell = (Element) rows.get(r + morerows)
1696 .selectSingleNode(
1697 JRSTLexer.CELL + "[@"
1698 + JRSTLexer.CELL_INDEX_START
1699 + "=" + cellStart + "]");
1700 text += tmpCell.getText();
1701
1702 tmpCell.addAttribute("used", TRUE);
1703 } while (!TRUE.equals(tmpCell
1704 .attributeValue(JRSTLexer.CELL_END)));
1705
1706 if (morerows > 0) {
1707 entry
1708 .addAttribute("morerows", String
1709 .valueOf(morerows));
1710 }
1711
1712
1713
1714 int morecols = 0;
1715 tmpCell = cells.get(c + morecols);
1716 int cellEnd = Integer.parseInt(tmpCell
1717 .attributeValue(JRSTLexer.CELL_INDEX_END));
1718 while (cellEnd + 1 != beginCell[c + morecols + 1]) {
1719 morecols++;
1720
1721
1722
1723
1724 }
1725 if (morecols > 0) {
1726 entry
1727 .addAttribute("morecols", String
1728 .valueOf(morecols));
1729 }
1730
1731 Document doc = newJRSTReader(new StringReader(text));
1732 entry.appendContent(doc.getRootElement());
1733 }
1734 }
1735 if (TRUE.equals(rows.get(r).attributeValue(
1736 JRSTLexer.ROW_END_HEADER))) {
1737 rowList = tgroup.addElement(TBODY);
1738 }
1739 }
1740
1741 return result;
1742 }
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761 private Element composeBulletList(JRSTLexer lexer) throws Exception {
1762 Element item = lexer.peekBulletList();
1763 Element result = DocumentHelper.createElement(BULLET_LIST);
1764 copyLevel(item, result);
1765 result.addAttribute(BULLET, item.attributeValue(BULLET));
1766 while (itemEquals(BULLET_LIST, item) && isSameLevel(item, result)
1767 && hasSameAttribute(item, result, BULLET)) {
1768 lexer.remove();
1769 Element bullet = result.addElement(LIST_ITEM);
1770 copyLevel(item, bullet);
1771 bullet.addElement(PARAGRAPH).addAttribute(ATTR_INLINE, TRUE)
1772 .setText(item.getText());
1773 composeBody(lexer, bullet);
1774
1775 item = lexer.peekBulletList();
1776 }
1777 return result;
1778 }
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793 private Element composeEnumeratedList(JRSTLexer lexer) throws Exception {
1794 Element item = lexer.peekEnumeratedList();
1795 Element result = DocumentHelper.createElement(ENUMERATED_LIST);
1796 copyLevel(item, result);
1797 String enumType = item.attributeValue(ENUMTYPE);
1798 if (!enumType.equals("arabic")) {
1799 result.addAttribute(START, item.attributeValue(START));
1800 }
1801 result.addAttribute(PREFIX, item.attributeValue(PREFIX));
1802 result.addAttribute(SUFFIX, item.attributeValue(SUFFIX));
1803 result.addAttribute(ENUMTYPE, enumType);
1804 while (itemEquals(ENUMERATED_LIST, item)
1805 && isSameLevel(item, result)
1806 && hasSameAttribute(item, result, PREFIX, SUFFIX)
1807 && (AUTO.equals(item.attributeValue(ENUMTYPE)) || hasSameAttribute(
1808 item, result, ENUMTYPE))) {
1809 lexer.remove();
1810 Element e = result.addElement(LIST_ITEM);
1811 copyLevel(item, e);
1812 e.addElement(PARAGRAPH).addAttribute(ATTR_INLINE, TRUE).setText(
1813 item.getText());
1814 composeBody(lexer, e);
1815
1816 item = lexer.peekEnumeratedList();
1817 }
1818 return result;
1819 }
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831 private Element composeDefinitionList(JRSTLexer lexer) throws Exception {
1832 Element item = lexer.peekBodyElement();
1833 Element result = DocumentHelper.createElement(DEFINITION_LIST);
1834 copyLevel(item, result);
1835 while (itemEquals(DEFINITION_LIST, item) && isSameLevel(item, result)) {
1836 lexer.remove();
1837 Element def = result.addElement(DEFINITION_LIST_ITEM);
1838 copyLevel(item, def);
1839
1840 Element term = def.addElement(TERM);
1841 copyLevel(item, term);
1842 term.addAttribute(ATTR_INLINE, TRUE).setText(
1843 item.attributeValue("term"));
1844
1845 String[] classifiers = StringUtil.split(item
1846 .attributeValue("classifiers"), " : ");
1847 for (String classifierText : classifiers) {
1848 Element classifier = def.addElement("classifier");
1849 copyLevel(item, classifier);
1850 classifier.addAttribute(ATTR_INLINE, TRUE).setText(
1851 classifierText);
1852 }
1853
1854 Element definition = def.addElement(DEFINITION);
1855 definition.addElement(PARAGRAPH).addAttribute(ATTR_INLINE, TRUE)
1856 .setText(item.getText());
1857 copyLevel(item, definition);
1858
1859 composeBody(lexer, definition);
1860
1861 item = lexer.peekBodyElement();
1862 }
1863 return result;
1864 }
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877 private Element composeFieldList(JRSTLexer lexer) throws Exception {
1878 Element item = lexer.peekBodyElement();
1879 Element result = DocumentHelper.createElement(FIELD_LIST);
1880 copyLevel(item, result);
1881 while (itemEquals(FIELD_LIST, item) && isSameLevel(item, result)) {
1882 Element field = composeFieldItemList(lexer);
1883 result.add(field);
1884 item = lexer.peekBodyElement();
1885 }
1886 return result;
1887 }
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902 private Element composeFieldItemList(JRSTLexer lexer) throws Exception {
1903 Element item = lexer.peekFieldList();
1904 if (itemEquals(FIELD_LIST, item)) {
1905 lexer.remove();
1906 Element field = DocumentHelper.createElement(FIELD);
1907 copyLevel(item, field);
1908 Element fieldName = field.addElement(FIELD_NAME);
1909 copyLevel(item, fieldName);
1910 fieldName.addAttribute(ATTR_INLINE, TRUE).setText(
1911 item.attributeValue(NAME));
1912 Element fieldBody = field.addElement(FIELD_BODY);
1913 fieldBody.addElement(PARAGRAPH).addAttribute(ATTR_INLINE, TRUE)
1914 .setText(item.getText());
1915 copyLevel(item, fieldBody);
1916 composeBody(lexer, fieldBody);
1917
1918 return field;
1919 } else {
1920 throw new DocumentException("Waiting for " + FIELD_LIST
1921 + " and found " + item.getName());
1922 }
1923 }
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935 private Element composeSection(JRSTLexer lexer) throws Exception {
1936 Element result = DocumentHelper.createElement(SECTION);
1937 Element firstTitle = null;
1938
1939 Element item = null;
1940
1941
1942 item = lexer.peekTitle();
1943 if (itemEquals(TITLE, item, true, lexer.eof())) {
1944 lexer.remove();
1945 firstTitle = item;
1946 Element title = result.addElement(TITLE);
1947 copyLevel(item, result);
1948 copyLevel(item, title);
1949 title.addAttribute(ATTR_INLINE, TRUE).setText(item.getText().trim());
1950 result.addAttribute(ATTR_IDS, item.getText().replaceAll("\\W+", " ")
1951 .trim().toLowerCase().replaceAll("\\W+", "-"));
1952 result.addAttribute(NAME, item.getText().toLowerCase().trim());
1953 eTitle.add(title);
1954 }
1955
1956
1957 item = lexer.peekTitle();
1958 while (itemNotEquals(TITLE, item) && !lexer.eof()) {
1959 composeBody(lexer, result);
1960 item = lexer.peekTitle();
1961 }
1962
1963
1964 item = lexer.peekTitle();
1965 while (itemEquals(TITLE, item) && isUpperLevel(item, firstTitle)) {
1966 Element section = composeSection(lexer);
1967 result.add(section);
1968 item = lexer.peekTitle();
1969 }
1970
1971 return result;
1972 }
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983 private boolean isUpperLevel(Element subSection, Element section)
1984 throws DocumentException {
1985
1986
1987
1988
1989
1990
1991 int subSectionLevel = Integer.parseInt(subSection
1992 .attributeValue(LEVEL));
1993 int sectionLevel = Integer.parseInt(section.attributeValue(LEVEL));
1994 boolean result = subSectionLevel > sectionLevel;
1995 return result;
1996 }
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006 private boolean isSameLevel(Element subSection, Element section)
2007 throws DocumentException {
2008
2009
2010
2011
2012 int subSectionLevel = Integer.parseInt(subSection
2013 .attributeValue(LEVEL));
2014 int sectionLevel = Integer.parseInt(section.attributeValue(LEVEL));
2015 boolean result = subSectionLevel == sectionLevel;
2016 return result;
2017 }
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028 private boolean hasSameAttribute(Element e1, Element e2, String... attnames) {
2029 boolean result = true;
2030 for (String attname : attnames) {
2031 String a1 = e1.attributeValue(attname);
2032 String a2 = e2.attributeValue(attname);
2033 if (!ObjectUtils.equals(a1, a2)) {
2034 result = false;
2035 break;
2036 }
2037 }
2038 return result;
2039 }
2040
2041
2042
2043
2044
2045
2046
2047
2048 private void copyLevel(Element from, Element to) throws DocumentException {
2049 String level = from.attributeValue(LEVEL);
2050 if (level == null) {
2051 throw new DocumentException("Element without level: " + from);
2052 }
2053 to.addAttribute(LEVEL, level);
2054 }
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064 private boolean itemEquals(String name, Element e) throws DocumentException {
2065 boolean result = itemEquals(name, e, false, false);
2066 return result;
2067 }
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079 private boolean itemEquals(String name, Element e, boolean throwError,
2080 boolean eof) throws DocumentException {
2081 boolean result = e != null && name.equals(e.getName());
2082 if (ERROR_MISSING_ITEM && !result && throwError && !eof) {
2083 throw new DocumentException("Malformed document waiting " + name
2084 + " and found " + (e != null ? e.getName() : "null"));
2085 }
2086 return result;
2087 }
2088
2089
2090
2091
2092
2093
2094
2095
2096 private boolean itemNotEquals(String name, Element e) {
2097 boolean result = e == null || !name.equals(e.getName());
2098 return result;
2099 }
2100
2101 private Document newJRSTReader(Reader r) throws Exception {
2102 JRSTReader reader = new JRSTReader();
2103 reader.setVariable(idMax, symbolMax, symbolMaxRef, lblFootnotes,
2104 lblFootnotesRef, eFootnotes, eTarget, eTargetAnonymous,
2105 eTargetAnonymousCopy);
2106
2107 return reader.read(r);
2108
2109 }
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127 public void setVariable(int idMax, int symbolMax, int symbolMaxRef,
2128 LinkedList<Integer> lblFootnotes,
2129 LinkedList<Integer> lblFootnotesRef,
2130 LinkedList<Element> eFootnotes, LinkedList<Element> eTarget,
2131 LinkedList<Element> eTargetAnonymous,
2132 LinkedList<Element> eTargetAnonymousCopy) {
2133 this.idMax = idMax;
2134 this.symbolMax = symbolMax;
2135 this.symbolMaxRef = symbolMaxRef;
2136 this.lblFootnotes = lblFootnotes;
2137 this.lblFootnotesRef = lblFootnotesRef;
2138 this.eFootnotes = eFootnotes;
2139 this.eTarget = eTarget;
2140 this.eTargetAnonymous = eTargetAnonymous;
2141 this.eTargetAnonymousCopy = eTargetAnonymousCopy;
2142 }
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153 private void inline(Element e) throws DocumentException, UnsupportedEncodingException {
2154 String text = e.getText();
2155
2156 text = StringEscapeUtils.escapeXml(text);
2157
2158
2159
2160 Map<String, String> temporaries = new HashMap<String, String>();
2161 Matcher matcher = REGEX_LITERAL.matcher(text);
2162 int index = 0;
2163 while (matcher.find()) {
2164 int start = matcher.start();
2165 int end = matcher.end();
2166 String literal = "<" + LITERAL + ">" + matcher.group(1) + "</"
2167 + LITERAL + ">";
2168 String key = LITERAL + index++;
2169 temporaries.put(key, literal);
2170 text = text.substring(0, start) + "<tmp>" + key + "</tmp>"
2171 + text.substring(end);
2172 matcher = REGEX_LITERAL.matcher(text);
2173 }
2174
2175
2176
2177 matcher = REGEX_INLINE_REFERENCE.matcher(text);
2178 index = 0;
2179 while (matcher.find()) {
2180 int start = matcher.start();
2181 int end = matcher.end();
2182 Element ref = DocumentHelper.createElement(REFERENCE);
2183 ref.addAttribute(REFURI, StringEscapeUtils.unescapeXml(matcher.group(2)));
2184 ref.setText(StringEscapeUtils.unescapeXml(matcher.group(1)));
2185 String key = "inlineReference" + index++;
2186 temporaries.put(key, ref.asXML());
2187 text = text.substring(0, start) + "<tmp>" + key + "</tmp>"
2188 + text.substring(end);
2189 matcher = REGEX_INLINE_REFERENCE.matcher(text);
2190
2191 }
2192
2193 text = REGEX_EMAIL.matcher(text).replaceAll(
2194 "$1<" + REFERENCE + " refuri='mailto:$2'>$2</" + REFERENCE
2195 + ">$3");
2196 text = REGEX_STRONG.matcher(text).replaceAll(
2197 "<" + STRONG + ">$1</" + STRONG + ">");
2198 text = REGEX_EMPHASIS.matcher(text).replaceAll(
2199 "<" + EMPHASIS + ">$1</" + EMPHASIS + ">");
2200 text = REGEX_REFERENCE.matcher(text).replaceAll(
2201 "<" + REFERENCE + " refuri='$1'>$1</" + REFERENCE + ">$2");
2202
2203 matcher = REGEX_FOOTNOTE_REFERENCE.matcher(text);
2204 while (matcher.find()) {
2205 String txtDebut = text.substring(0, matcher.start());
2206 String txtFin = text.substring(matcher.end()-1, text.length()-1);
2207 Element footnote = DocumentHelper.createElement(FOOTNOTE_REFERENCE);
2208 String sFootnote = matcher.group();
2209 boolean done = false;
2210 for (int i = 0; i < sFootnote.length() && !done; i++) {
2211 if (sFootnote.charAt(i) == ']') {
2212 String id = sFootnote.substring(1, i);
2213 if (id.equals("*")) {
2214 int nb = Math.abs(symbolMaxRef / 10) + 1;
2215 char symbol = FOOTNOTE_SYMBOL.charAt(symbolMaxRef % 10);
2216 String label = "";
2217 for (int j = 0; j < nb; j++) {
2218 label += symbol;
2219 }
2220 symbolMaxRef++;
2221 footnote.addAttribute(AUTO, "*");
2222 for (int j = 0; j < eFootnotes.size(); j++) {
2223 Element eFootnote = eFootnotes.get(j);
2224 if (eFootnote.attributeValue(LABEL).equals(label)) {
2225
2226 footnote.addAttribute(ATTR_IDS, eFootnote
2227 .attributeValue(BACKREFS));
2228 footnote.addAttribute(ATTR_REFID, eFootnote
2229 .attributeValue(ATTR_IDS));
2230
2231 }
2232 }
2233 footnote.setText(label);
2234
2235 } else if (id.matches("[1-9]+")) {
2236
2237 for (int j = 0; j < eFootnotes.size(); j++) {
2238 Element eFootnote = eFootnotes.get(j);
2239 if (eFootnote.attributeValue(LABEL).equals(id)) {
2240 footnote.addAttribute(ATTR_IDS, eFootnote
2241 .attributeValue(BACKREFS));
2242 footnote.addAttribute(ATTR_REFID, eFootnote
2243 .attributeValue(ATTR_IDS));
2244 }
2245 }
2246 footnote.setText(id);
2247 lblFootnotesRef.add(Integer.parseInt(id));
2248
2249 } else if (id.equals("#")) {
2250 int lblMax = 0;
2251 for (int j = 0; j < lblFootnotesRef.size(); j++) {
2252 lblMax = Math.max(lblMax, lblFootnotesRef.get(j));
2253 }
2254
2255 boolean[] lbls = new boolean[lblMax];
2256 for (int j = 0; j < lbls.length; j++) {
2257 lbls[j] = false;
2258 }
2259 for (int j = 0; j < lblFootnotesRef.size(); j++) {
2260 lbls[lblFootnotesRef.get(j) - 1] = true;
2261 }
2262 boolean valide = false;
2263 do {
2264 boolean trouve = false;
2265 String label = null;
2266 for (int j = 0; j < lbls.length && !trouve; j++) {
2267
2268 if (!lbls[j]) {
2269 trouve = true;
2270 label = "" + (j + 1);
2271 }
2272 }
2273 if (!trouve) {
2274 label = "" + (lbls.length + 1);
2275 }
2276 footnote.addAttribute(AUTO, "1");
2277 for (int j = 0; j < eFootnotes.size(); j++) {
2278 Element eFootnote = eFootnotes.get(j);
2279 if (eFootnote.attributeValue(LABEL).equals(
2280 label)) {
2281 if (!(eFootnote.attributeValue(TYPE)
2282 .equals(AUTONUMLABEL))) {
2283 footnote.addAttribute(ATTR_IDS, eFootnote
2284 .attributeValue(BACKREFS));
2285 footnote.addAttribute(ATTR_REFID,
2286 eFootnote.attributeValue(ATTR_IDS));
2287 footnote.setText(label);
2288 lblFootnotesRef.add(Integer
2289 .parseInt(label));
2290 valide = true;
2291 } else {
2292 valide = false;
2293 lbls[Integer.parseInt(label) - 1] = true;
2294 }
2295 }
2296 }
2297 } while (!valide);
2298
2299 }
2300
2301 else {
2302 footnote.addAttribute(AUTO, "1");
2303
2304 String name = id.substring(1);
2305 boolean trouve = false;
2306 for (int j = 0; j < eFootnotes.size() && !trouve; j++) {
2307 Element eFootnote = eFootnotes.get(j);
2308 if (eFootnote.attributeValue(NAMES).equals(name)) {
2309 footnote.addAttribute(ATTR_IDS, eFootnote
2310 .attributeValue(BACKREFS));
2311 footnote.addAttribute(ATTR_REFID, eFootnote
2312 .attributeValue(ATTR_IDS));
2313 String label = eFootnote
2314 .attributeValue(LABEL);
2315 footnote.setText(label);
2316 lblFootnotesRef.add(Integer.parseInt(label));
2317 trouve = true;
2318 }
2319 }
2320
2321 footnote.addAttribute(NAMES, name);
2322 }
2323 done = true;
2324 }
2325 }
2326 text = txtDebut + footnote.asXML() + txtFin;
2327 matcher = REGEX_FOOTNOTE_REFERENCE.matcher(text);
2328 }
2329
2330 matcher = REGEX_ANONYMOUS_HYPERLINK_REFERENCE.matcher(text);
2331 while (matcher.find()) {
2332 String txtDebut = text.substring(0, matcher.start());
2333 String txtFin = text.substring(matcher.end(), text.length());
2334 String ref = text.substring(matcher.start(), matcher.end() - 2);
2335 ref = ref.replaceAll("`", "");
2336 Element anonym = DocumentHelper.createElement(REFERENCE);
2337 anonym.addAttribute(ANONYMOUS, "1");
2338 anonym.addAttribute(NAME, ref.trim());
2339 if (!eTargetAnonymous.isEmpty()) {
2340 Element target = eTargetAnonymous.getFirst();
2341 eTargetAnonymous.removeFirst();
2342 anonym.addAttribute(REFURI, target.attributeValue(REFURI));
2343 }
2344 anonym.setText(ref);
2345 text = txtDebut + anonym.asXML() + txtFin;
2346 matcher = REGEX_ANONYMOUS_HYPERLINK_REFERENCE.matcher(text);
2347 }
2348
2349 matcher = REGEX_HYPERLINK_REFERENCE.matcher(text);
2350 while (matcher.find()) {
2351 String txtDebut = text.substring(0, matcher.start());
2352 String txtFin = text.substring(matcher.end(), text.length());
2353 String ref = text.substring(matcher.start(), matcher.end() - 1);
2354 ref = StringEscapeUtils.unescapeXml(ref);
2355 ref = ref.replaceAll("('|_)", "");
2356 ref = ref.replaceAll("`", "");
2357 Element hyper = DocumentHelper.createElement(REFERENCE);
2358 hyper.addAttribute(NAME, ref);
2359 boolean trouve = false;
2360 for (int i = 0; i < eTarget.size() && !trouve; i++) {
2361 Element el = eTarget.get(i);
2362 String refTmp = URLEncoder.encode(ref.replaceAll("\\s", "-").toLowerCase(), "UTF-8");
2363 if (el.attributeValue(ID).equalsIgnoreCase((refTmp))) {
2364 hyper.addAttribute(REFURI, el.attributeValue(REFURI));
2365 trouve = true;
2366 }
2367 }
2368 if (!trouve) {
2369 hyper.addAttribute(ATTR_REFID, ref);
2370 }
2371 hyper.setText(ref);
2372 text = txtDebut + hyper.asXML() + " " + txtFin;
2373 matcher = REGEX_HYPERLINK_REFERENCE.matcher(text);
2374
2375 }
2376
2377
2378 matcher = REGEX_SUBSTITUTION_REFERENCE.matcher(text);
2379 int begin = 0;
2380 while (matcher.find(begin)) {
2381 String start = text.substring(0, matcher.start());
2382 String end = text.substring(matcher.end());
2383 String ref = matcher.group(1);
2384
2385 Node subst = e.selectSingleNode("//" + SUBSTITUTION_DEFINITION
2386 + "[@name='" + ref + "']/child::node()");
2387
2388 if (subst == null) {
2389 text = start + "|" + ref + "|";
2390 } else {
2391 text = start + subst.asXML();
2392 }
2393
2394 begin = text.length();
2395 text += end;
2396 matcher = REGEX_SUBSTITUTION_REFERENCE.matcher(text);
2397
2398 }
2399
2400 Pattern p = Pattern.compile("<tmp>([^<>]+)</tmp>");
2401
2402 matcher = p.matcher(text);
2403 while (matcher.find()) {
2404 String start = text.substring(0, matcher.start());
2405 String end = text.substring(matcher.end());
2406
2407 String tempKey = matcher.group(1);
2408 text = start + temporaries.get(tempKey) + end;
2409 matcher = p.matcher(text);
2410 }
2411
2412 String resultElementText = text.trim();
2413 Element result = DocumentHelper.parseText(
2414 "<TMP>" + resultElementText + "</TMP>").getRootElement();
2415
2416 e.setText("");
2417 e.appendContent(result);
2418 }
2419 }