1 package org.apache.maven.doxia.sink.impl;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.PrintWriter;
23 import java.io.StringWriter;
24 import java.io.Writer;
25 import java.util.ArrayList;
26 import java.util.EmptyStackException;
27 import java.util.Enumeration;
28 import java.util.HashMap;
29 import java.util.LinkedList;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Objects;
33 import java.util.Stack;
34
35 import javax.swing.text.MutableAttributeSet;
36 import javax.swing.text.html.HTML.Attribute;
37 import javax.swing.text.html.HTML.Tag;
38
39 import org.apache.maven.doxia.markup.HtmlMarkup;
40 import org.apache.maven.doxia.markup.Markup;
41 import org.apache.maven.doxia.sink.Sink;
42 import org.apache.maven.doxia.sink.SinkEventAttributes;
43 import org.apache.maven.doxia.util.DoxiaUtils;
44 import org.apache.maven.doxia.util.HtmlTools;
45
46 import org.codehaus.plexus.util.StringUtils;
47 import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51
52
53
54 public class Xhtml5BaseSink
55 extends AbstractXmlSink
56 implements HtmlMarkup
57 {
58 private static final Logger LOGGER = LoggerFactory.getLogger( Xhtml5BaseSink.class );
59
60
61
62
63
64
65 private final PrintWriter writer;
66
67
68 private StringBuffer textBuffer = new StringBuffer();
69
70
71 private boolean headFlag;
72
73
74 protected Stack<Tag> contentStack = new Stack<>();
75
76
77 protected Stack<List<Tag>> inlineStack = new Stack<>();
78
79
80 private boolean paragraphFlag;
81
82
83 private boolean verbatimFlag;
84
85
86 private final LinkedList<int[]> cellJustifStack;
87
88
89 private final LinkedList<Boolean> isCellJustifStack;
90
91
92 private final LinkedList<Integer> cellCountStack;
93
94
95 private boolean evenTableRow = true;
96
97
98 private final LinkedList<StringWriter> tableContentWriterStack;
99
100 private final LinkedList<StringWriter> tableCaptionWriterStack;
101
102 private final LinkedList<PrettyPrintXMLWriter> tableCaptionXMLWriterStack;
103
104
105 private final LinkedList<String> tableCaptionStack;
106
107
108 protected MutableAttributeSet tableAttributes;
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 protected boolean tableRows = false;
124
125
126
127
128
129
130
131
132
133
134 public Xhtml5BaseSink( Writer out )
135 {
136 this.writer = new PrintWriter( out );
137
138 this.cellJustifStack = new LinkedList<>();
139 this.isCellJustifStack = new LinkedList<>();
140 this.cellCountStack = new LinkedList<>();
141 this.tableContentWriterStack = new LinkedList<>();
142 this.tableCaptionWriterStack = new LinkedList<>();
143 this.tableCaptionXMLWriterStack = new LinkedList<>();
144 this.tableCaptionStack = new LinkedList<>();
145
146 init();
147 }
148
149
150
151
152
153
154
155
156
157
158 protected StringBuffer getTextBuffer()
159 {
160 return this.textBuffer;
161 }
162
163
164
165
166
167
168 protected void setHeadFlag( boolean headFlag )
169 {
170 this.headFlag = headFlag;
171 }
172
173
174
175
176
177
178 protected boolean isHeadFlag()
179 {
180 return this.headFlag ;
181 }
182
183
184
185
186
187
188 protected void setVerbatimFlag( boolean verb )
189 {
190 this.verbatimFlag = verb;
191 }
192
193
194
195
196
197
198 protected boolean isVerbatimFlag()
199 {
200 return this.verbatimFlag ;
201 }
202
203
204
205
206
207
208 protected void setCellJustif( int[] justif )
209 {
210 this.cellJustifStack.addLast( justif );
211 this.isCellJustifStack.addLast( Boolean.TRUE );
212 }
213
214
215
216
217
218
219 protected int[] getCellJustif()
220 {
221 return this.cellJustifStack.getLast();
222 }
223
224
225
226
227
228
229 protected void setCellCount( int count )
230 {
231 this.cellCountStack.addLast( count );
232 }
233
234
235
236
237
238
239 protected int getCellCount()
240 {
241 return Integer.parseInt( this.cellCountStack.getLast().toString() );
242 }
243
244
245 @Override
246 protected void init()
247 {
248 super.init();
249
250 resetTextBuffer();
251
252 this.cellJustifStack.clear();
253 this.isCellJustifStack.clear();
254 this.cellCountStack.clear();
255 this.tableContentWriterStack.clear();
256 this.tableCaptionWriterStack.clear();
257 this.tableCaptionXMLWriterStack.clear();
258 this.tableCaptionStack.clear();
259 this.inlineStack.clear();
260
261 this.headFlag = false;
262 this.paragraphFlag = false;
263 this.verbatimFlag = false;
264
265 this.evenTableRow = true;
266 this.tableAttributes = null;
267 this.tableRows = false;
268 }
269
270
271
272
273 protected void resetTextBuffer()
274 {
275 this.textBuffer = new StringBuffer();
276 }
277
278
279
280
281
282
283 @Override
284 public void article()
285 {
286 article( null );
287 }
288
289
290 @Override
291 public void article( SinkEventAttributes attributes )
292 {
293 MutableAttributeSet atts = SinkUtils.filterAttributes(
294 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
295
296 writeStartTag( HtmlMarkup.ARTICLE, atts );
297 }
298
299
300 @Override
301 public void article_()
302 {
303 writeEndTag( HtmlMarkup.ARTICLE );
304 }
305
306
307 @Override
308 public void navigation()
309 {
310 navigation( null );
311 }
312
313
314 @Override
315 public void navigation( SinkEventAttributes attributes )
316 {
317 MutableAttributeSet atts = SinkUtils.filterAttributes(
318 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
319
320 writeStartTag( HtmlMarkup.NAV, atts );
321 }
322
323
324 @Override
325 public void navigation_()
326 {
327 writeEndTag( HtmlMarkup.NAV );
328 }
329
330
331 @Override
332 public void sidebar()
333 {
334 sidebar( null );
335 }
336
337
338 @Override
339 public void sidebar( SinkEventAttributes attributes )
340 {
341 MutableAttributeSet atts = SinkUtils.filterAttributes(
342 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
343
344 writeStartTag( HtmlMarkup.ASIDE, atts );
345 }
346
347
348 @Override
349 public void sidebar_()
350 {
351 writeEndTag( HtmlMarkup.ASIDE );
352 }
353
354
355 @Override
356 public void section( int level, SinkEventAttributes attributes )
357 {
358 onSection( level, attributes );
359 }
360
361
362 @Override
363 public void sectionTitle( int level, SinkEventAttributes attributes )
364 {
365 onSectionTitle( level, attributes );
366 }
367
368
369 @Override
370 public void sectionTitle_( int level )
371 {
372 onSectionTitle_( level );
373 }
374
375
376 @Override
377 public void section_( int level )
378 {
379 onSection_( level );
380 }
381
382
383 @Override
384 public void section1()
385 {
386 onSection( SECTION_LEVEL_1, null );
387 }
388
389
390 @Override
391 public void sectionTitle1()
392 {
393 onSectionTitle( SECTION_LEVEL_1, null );
394 }
395
396
397 @Override
398 public void sectionTitle1_()
399 {
400 onSectionTitle_( SECTION_LEVEL_1 );
401 }
402
403
404 @Override
405 public void section1_()
406 {
407 onSection_( SECTION_LEVEL_1 );
408 }
409
410
411 @Override
412 public void section2()
413 {
414 onSection( SECTION_LEVEL_2, null );
415 }
416
417
418 @Override
419 public void sectionTitle2()
420 {
421 onSectionTitle( SECTION_LEVEL_2, null );
422 }
423
424
425 @Override
426 public void sectionTitle2_()
427 {
428 onSectionTitle_( SECTION_LEVEL_2 );
429 }
430
431
432 @Override
433 public void section2_()
434 {
435 onSection_( SECTION_LEVEL_2 );
436 }
437
438
439 @Override
440 public void section3()
441 {
442 onSection( SECTION_LEVEL_3, null );
443 }
444
445
446 @Override
447 public void sectionTitle3()
448 {
449 onSectionTitle( SECTION_LEVEL_3, null );
450 }
451
452
453 @Override
454 public void sectionTitle3_()
455 {
456 onSectionTitle_( SECTION_LEVEL_3 );
457 }
458
459
460 @Override
461 public void section3_()
462 {
463 onSection_( SECTION_LEVEL_3 );
464 }
465
466
467 @Override
468 public void section4()
469 {
470 onSection( SECTION_LEVEL_4, null );
471 }
472
473
474 @Override
475 public void sectionTitle4()
476 {
477 onSectionTitle( SECTION_LEVEL_4, null );
478 }
479
480
481 @Override
482 public void sectionTitle4_()
483 {
484 onSectionTitle_( SECTION_LEVEL_4 );
485 }
486
487
488 @Override
489 public void section4_()
490 {
491 onSection_( SECTION_LEVEL_4 );
492 }
493
494
495 @Override
496 public void section5()
497 {
498 onSection( SECTION_LEVEL_5, null );
499 }
500
501
502 @Override
503 public void sectionTitle5()
504 {
505 onSectionTitle( SECTION_LEVEL_5, null );
506 }
507
508
509 @Override
510 public void sectionTitle5_()
511 {
512 onSectionTitle_( SECTION_LEVEL_5 );
513 }
514
515
516 @Override
517 public void section5_()
518 {
519 onSection_( SECTION_LEVEL_5 );
520 }
521
522
523
524
525
526
527
528 protected void onSection( int depth, SinkEventAttributes attributes )
529 {
530 if ( depth >= SECTION_LEVEL_1 && depth <= SECTION_LEVEL_5 )
531 {
532 MutableAttributeSet att = new SinkEventAttributeSet();
533 att.addAttributes( SinkUtils.filterAttributes(
534 attributes, SinkUtils.SINK_BASE_ATTRIBUTES ) );
535
536 writeStartTag( HtmlMarkup.SECTION, att );
537 }
538 }
539
540
541
542
543
544
545
546 protected void onSection_( int depth )
547 {
548 if ( depth >= SECTION_LEVEL_1 && depth <= SECTION_LEVEL_5 )
549 {
550 writeEndTag( HtmlMarkup.SECTION );
551 }
552 }
553
554
555
556
557
558
559
560
561
562
563
564
565 protected void onSectionTitle( int depth, SinkEventAttributes attributes )
566 {
567 MutableAttributeSet atts = SinkUtils.filterAttributes(
568 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
569
570 if ( depth == SECTION_LEVEL_1 )
571 {
572 writeStartTag( HtmlMarkup.H2, atts );
573 }
574 else if ( depth == SECTION_LEVEL_2 )
575 {
576 writeStartTag( HtmlMarkup.H3, atts );
577 }
578 else if ( depth == SECTION_LEVEL_3 )
579 {
580 writeStartTag( HtmlMarkup.H4, atts );
581 }
582 else if ( depth == SECTION_LEVEL_4 )
583 {
584 writeStartTag( HtmlMarkup.H5, atts );
585 }
586 else if ( depth == SECTION_LEVEL_5 )
587 {
588 writeStartTag( HtmlMarkup.H6, atts );
589 }
590 }
591
592
593
594
595
596
597
598
599
600
601
602 protected void onSectionTitle_( int depth )
603 {
604 if ( depth == SECTION_LEVEL_1 )
605 {
606 writeEndTag( HtmlMarkup.H2 );
607 }
608 else if ( depth == SECTION_LEVEL_2 )
609 {
610 writeEndTag( HtmlMarkup.H3 );
611 }
612 else if ( depth == SECTION_LEVEL_3 )
613 {
614 writeEndTag( HtmlMarkup.H4 );
615 }
616 else if ( depth == SECTION_LEVEL_4 )
617 {
618 writeEndTag( HtmlMarkup.H5 );
619 }
620 else if ( depth == SECTION_LEVEL_5 )
621 {
622 writeEndTag( HtmlMarkup.H6 );
623 }
624 }
625
626
627 @Override
628 public void header()
629 {
630 header( null );
631 }
632
633
634 @Override
635 public void header( SinkEventAttributes attributes )
636 {
637 MutableAttributeSet atts = SinkUtils.filterAttributes(
638 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
639
640 writeStartTag( HtmlMarkup.HEADER, atts );
641 }
642
643
644 @Override
645 public void header_()
646 {
647 writeEndTag( HtmlMarkup.HEADER );
648 }
649
650
651 @Override
652 public void content()
653 {
654 content( (SinkEventAttributes) null );
655 }
656
657
658 @Override
659 public void content( SinkEventAttributes attributes )
660 {
661 MutableAttributeSet atts = SinkUtils.filterAttributes(
662 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
663
664 if ( contentStack.empty() )
665 {
666 writeStartTag( contentStack.push( HtmlMarkup.MAIN ), atts );
667 }
668 else
669 {
670 if ( atts == null )
671 {
672 atts = new SinkEventAttributeSet( 1 );
673 }
674
675 if ( !atts.isDefined( SinkEventAttributes.CLASS ) )
676 {
677 atts.addAttribute( SinkEventAttributes.CLASS, "content" );
678 }
679
680 writeStartTag( contentStack.push( HtmlMarkup.DIV ), atts );
681 }
682 }
683
684
685 @Override
686 public void content_()
687 {
688 try
689 {
690 writeEndTag( contentStack.pop() );
691 }
692 catch ( EmptyStackException ese )
693 {
694
695 }
696 }
697
698
699 @Override
700 public void footer()
701 {
702 footer( null );
703 }
704
705
706 @Override
707 public void footer( SinkEventAttributes attributes )
708 {
709 MutableAttributeSet atts = SinkUtils.filterAttributes(
710 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
711
712 writeStartTag( HtmlMarkup.FOOTER, atts );
713 }
714
715
716 @Override
717 public void footer_()
718 {
719 writeEndTag( HtmlMarkup.FOOTER );
720 }
721
722
723
724
725
726
727
728
729
730 @Override
731 public void list()
732 {
733 list( null );
734 }
735
736
737
738
739
740 @Override
741 public void list( SinkEventAttributes attributes )
742 {
743 if ( paragraphFlag )
744 {
745
746
747
748 paragraph_();
749 }
750
751 MutableAttributeSet atts = SinkUtils.filterAttributes(
752 attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
753
754 writeStartTag( HtmlMarkup.UL, atts );
755 }
756
757
758
759
760
761 @Override
762 public void list_()
763 {
764 writeEndTag( HtmlMarkup.UL );
765 }
766
767
768
769
770
771 @Override
772 public void listItem()
773 {
774 listItem( null );
775 }
776
777
778
779
780
781 @Override
782 public void listItem( SinkEventAttributes attributes )
783 {
784 MutableAttributeSet atts = SinkUtils.filterAttributes(
785 attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
786
787 writeStartTag( HtmlMarkup.LI, atts );
788 }
789
790
791
792
793
794 @Override
795 public void listItem_()
796 {
797 writeEndTag( HtmlMarkup.LI );
798 }
799
800
801
802
803
804
805
806 @Override
807 public void numberedList( int numbering )
808 {
809 numberedList( numbering, null );
810 }
811
812
813
814
815
816
817
818 @Override
819 public void numberedList( int numbering, SinkEventAttributes attributes )
820 {
821 if ( paragraphFlag )
822 {
823
824
825
826 paragraph_();
827 }
828
829 String style;
830 switch ( numbering )
831 {
832 case NUMBERING_UPPER_ALPHA:
833 style = "upper-alpha";
834 break;
835 case NUMBERING_LOWER_ALPHA:
836 style = "lower-alpha";
837 break;
838 case NUMBERING_UPPER_ROMAN:
839 style = "upper-roman";
840 break;
841 case NUMBERING_LOWER_ROMAN:
842 style = "lower-roman";
843 break;
844 case NUMBERING_DECIMAL:
845 default:
846 style = "decimal";
847 }
848
849 MutableAttributeSet atts = SinkUtils.filterAttributes(
850 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
851
852 if ( atts == null )
853 {
854 atts = new SinkEventAttributeSet( 1 );
855 }
856
857 atts.addAttribute( Attribute.STYLE, "list-style-type: " + style );
858
859 writeStartTag( HtmlMarkup.OL, atts );
860 }
861
862
863
864
865
866 @Override
867 public void numberedList_()
868 {
869 writeEndTag( HtmlMarkup.OL );
870 }
871
872
873
874
875
876 @Override
877 public void numberedListItem()
878 {
879 numberedListItem( null );
880 }
881
882
883
884
885
886 @Override
887 public void numberedListItem( SinkEventAttributes attributes )
888 {
889 MutableAttributeSet atts = SinkUtils.filterAttributes(
890 attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
891
892 writeStartTag( HtmlMarkup.LI, atts );
893 }
894
895
896
897
898
899 @Override
900 public void numberedListItem_()
901 {
902 writeEndTag( HtmlMarkup.LI );
903 }
904
905
906
907
908
909 @Override
910 public void definitionList()
911 {
912 definitionList( null );
913 }
914
915
916
917
918
919 @Override
920 public void definitionList( SinkEventAttributes attributes )
921 {
922 if ( paragraphFlag )
923 {
924
925
926
927 paragraph_();
928 }
929
930 MutableAttributeSet atts = SinkUtils.filterAttributes(
931 attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
932
933 writeStartTag( HtmlMarkup.DL, atts );
934 }
935
936
937
938
939
940 @Override
941 public void definitionList_()
942 {
943 writeEndTag( HtmlMarkup.DL );
944 }
945
946
947
948
949
950 @Override
951 public void definedTerm( SinkEventAttributes attributes )
952 {
953 MutableAttributeSet atts = SinkUtils.filterAttributes(
954 attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
955
956 writeStartTag( HtmlMarkup.DT, atts );
957 }
958
959
960
961
962
963 @Override
964 public void definedTerm()
965 {
966 definedTerm( null );
967 }
968
969
970
971
972
973 @Override
974 public void definedTerm_()
975 {
976 writeEndTag( HtmlMarkup.DT );
977 }
978
979
980
981
982
983 @Override
984 public void definition()
985 {
986 definition( null );
987 }
988
989
990
991
992
993 @Override
994 public void definition( SinkEventAttributes attributes )
995 {
996 MutableAttributeSet atts = SinkUtils.filterAttributes(
997 attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
998
999 writeStartTag( HtmlMarkup.DD, atts );
1000 }
1001
1002
1003
1004
1005
1006 @Override
1007 public void definition_()
1008 {
1009 writeEndTag( HtmlMarkup.DD );
1010 }
1011
1012
1013 @Override
1014 public void figure()
1015 {
1016 figure( null );
1017 }
1018
1019
1020 @Override
1021 public void figure( SinkEventAttributes attributes )
1022 {
1023 writeStartTag( HtmlMarkup.FIGURE, attributes );
1024 }
1025
1026
1027 @Override
1028 public void figure_()
1029 {
1030 writeEndTag( HtmlMarkup.FIGURE );
1031 }
1032
1033
1034 @Override
1035 public void figureGraphics( String name )
1036 {
1037 figureGraphics( name, null );
1038 }
1039
1040
1041 @Override
1042 public void figureGraphics( String src, SinkEventAttributes attributes )
1043 {
1044 MutableAttributeSet filtered = SinkUtils.filterAttributes( attributes, SinkUtils.SINK_IMG_ATTRIBUTES );
1045 if ( filtered != null )
1046 {
1047 filtered.removeAttribute( Attribute.SRC.toString() );
1048 }
1049
1050 int count = ( attributes == null ? 1 : attributes.getAttributeCount() + 1 );
1051
1052 MutableAttributeSet atts = new SinkEventAttributeSet( count );
1053
1054 atts.addAttribute( Attribute.SRC, HtmlTools.escapeHTML( src, true ) );
1055 atts.addAttributes( filtered );
1056
1057 if ( atts.getAttribute( Attribute.ALT.toString() ) == null )
1058 {
1059 atts.addAttribute( Attribute.ALT.toString(), "" );
1060 }
1061
1062 writeStartTag( HtmlMarkup.IMG, atts, true );
1063 }
1064
1065
1066 @Override
1067 public void figureCaption()
1068 {
1069 figureCaption( null );
1070 }
1071
1072
1073 @Override
1074 public void figureCaption( SinkEventAttributes attributes )
1075 {
1076 writeStartTag( HtmlMarkup.FIGCAPTION, attributes );
1077 }
1078
1079
1080 @Override
1081 public void figureCaption_()
1082 {
1083 writeEndTag( HtmlMarkup.FIGCAPTION );
1084 }
1085
1086
1087
1088
1089
1090 @Override
1091 public void paragraph()
1092 {
1093 paragraph( null );
1094 }
1095
1096
1097
1098
1099
1100 @Override
1101 public void paragraph( SinkEventAttributes attributes )
1102 {
1103 paragraphFlag = true;
1104
1105 MutableAttributeSet atts = SinkUtils.filterAttributes(
1106 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
1107
1108 writeStartTag( HtmlMarkup.P, atts );
1109 }
1110
1111
1112
1113
1114
1115 @Override
1116 public void paragraph_()
1117 {
1118 if ( paragraphFlag )
1119 {
1120 writeEndTag( HtmlMarkup.P );
1121 paragraphFlag = false;
1122 }
1123 }
1124
1125
1126 @Override
1127 public void data( String value )
1128 {
1129 data( value, null );
1130 }
1131
1132
1133 @Override
1134 public void data( String value, SinkEventAttributes attributes )
1135 {
1136 MutableAttributeSet atts = SinkUtils.filterAttributes(
1137 attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
1138
1139 MutableAttributeSet att = new SinkEventAttributeSet();
1140 if ( value != null )
1141 {
1142 att.addAttribute( Attribute.VALUE, value );
1143 }
1144 att.addAttributes( atts );
1145
1146 writeStartTag( HtmlMarkup.DATA, att );
1147 }
1148
1149
1150 @Override
1151 public void data_()
1152 {
1153 writeEndTag( HtmlMarkup.DATA );
1154 }
1155
1156
1157 @Override
1158 public void time( String datetime )
1159 {
1160 time( datetime, null );
1161 }
1162
1163
1164 @Override
1165 public void time( String datetime, SinkEventAttributes attributes )
1166 {
1167 MutableAttributeSet atts = SinkUtils.filterAttributes(
1168 attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
1169
1170 MutableAttributeSet att = new SinkEventAttributeSet();
1171 if ( datetime != null )
1172 {
1173 att.addAttribute( "datetime", datetime );
1174 }
1175 att.addAttributes( atts );
1176
1177 writeStartTag( HtmlMarkup.TIME, att );
1178 }
1179
1180
1181 @Override
1182 public void time_()
1183 {
1184 writeEndTag( HtmlMarkup.TIME );
1185 }
1186
1187
1188
1189
1190
1191 @Override
1192 public void address()
1193 {
1194 address( null );
1195 }
1196
1197
1198
1199
1200
1201 @Override
1202 public void address( SinkEventAttributes attributes )
1203 {
1204 MutableAttributeSet atts = SinkUtils.filterAttributes(
1205 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
1206
1207 writeStartTag( HtmlMarkup.ADDRESS, atts );
1208 }
1209
1210
1211
1212
1213
1214 @Override
1215 public void address_()
1216 {
1217 writeEndTag( HtmlMarkup.ADDRESS );
1218 }
1219
1220
1221
1222
1223
1224 @Override
1225 public void blockquote()
1226 {
1227 blockquote( null );
1228 }
1229
1230
1231
1232
1233
1234 @Override
1235 public void blockquote( SinkEventAttributes attributes )
1236 {
1237 MutableAttributeSet atts = SinkUtils.filterAttributes(
1238 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
1239
1240 writeStartTag( HtmlMarkup.BLOCKQUOTE, atts );
1241 }
1242
1243
1244
1245
1246
1247 @Override
1248 public void blockquote_()
1249 {
1250 writeEndTag( HtmlMarkup.BLOCKQUOTE );
1251 }
1252
1253
1254
1255
1256
1257 @Override
1258 public void division()
1259 {
1260 division( null );
1261 }
1262
1263
1264
1265
1266
1267 @Override
1268 public void division( SinkEventAttributes attributes )
1269 {
1270 MutableAttributeSet atts = SinkUtils.filterAttributes(
1271 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
1272
1273 writeStartTag( HtmlMarkup.DIV, atts );
1274 }
1275
1276
1277
1278
1279
1280 @Override
1281 public void division_()
1282 {
1283 writeEndTag( HtmlMarkup.DIV );
1284 }
1285
1286
1287
1288
1289
1290
1291
1292
1293 @Override
1294 public void verbatim( SinkEventAttributes attributes )
1295 {
1296 if ( paragraphFlag )
1297 {
1298
1299
1300
1301 paragraph_();
1302 }
1303
1304 verbatimFlag = true;
1305
1306 MutableAttributeSet atts = SinkUtils.filterAttributes(
1307 attributes, SinkUtils.SINK_VERBATIM_ATTRIBUTES );
1308
1309 if ( atts == null )
1310 {
1311 atts = new SinkEventAttributeSet();
1312 }
1313
1314 boolean boxed = false;
1315
1316 if ( atts.isDefined( SinkEventAttributes.DECORATION ) )
1317 {
1318 boxed =
1319 "boxed".equals( atts.getAttribute( SinkEventAttributes.DECORATION ).toString() );
1320 }
1321
1322 SinkEventAttributes divAtts = null;
1323
1324 if ( boxed )
1325 {
1326 divAtts = new SinkEventAttributeSet( Attribute.CLASS.toString(), "source" );
1327 }
1328
1329 atts.removeAttribute( SinkEventAttributes.DECORATION );
1330
1331 writeStartTag( HtmlMarkup.DIV, divAtts );
1332 writeStartTag( HtmlMarkup.PRE, atts );
1333 }
1334
1335
1336
1337
1338
1339
1340 @Override
1341 public void verbatim_()
1342 {
1343 writeEndTag( HtmlMarkup.PRE );
1344 writeEndTag( HtmlMarkup.DIV );
1345
1346 verbatimFlag = false;
1347
1348 }
1349
1350
1351
1352
1353
1354 @Override
1355 public void horizontalRule()
1356 {
1357 horizontalRule( null );
1358 }
1359
1360
1361
1362
1363
1364 @Override
1365 public void horizontalRule( SinkEventAttributes attributes )
1366 {
1367 MutableAttributeSet atts = SinkUtils.filterAttributes(
1368 attributes, SinkUtils.SINK_HR_ATTRIBUTES );
1369
1370 writeSimpleTag( HtmlMarkup.HR, atts );
1371 }
1372
1373
1374 @Override
1375 public void table()
1376 {
1377
1378 table( null );
1379 }
1380
1381
1382 @Override
1383 public void table( SinkEventAttributes attributes )
1384 {
1385 this.tableContentWriterStack.addLast( new StringWriter() );
1386 this.tableRows = false;
1387
1388 if ( paragraphFlag )
1389 {
1390
1391
1392
1393 paragraph_();
1394 }
1395
1396
1397 if ( attributes == null )
1398 {
1399 this.tableAttributes = new SinkEventAttributeSet( 0 );
1400 }
1401 else
1402 {
1403 this.tableAttributes = SinkUtils.filterAttributes(
1404 attributes, SinkUtils.SINK_TABLE_ATTRIBUTES );
1405 }
1406 }
1407
1408
1409
1410
1411
1412 @Override
1413 public void table_()
1414 {
1415 this.tableRows = false;
1416
1417 writeEndTag( HtmlMarkup.TABLE );
1418
1419 if ( !this.cellCountStack.isEmpty() )
1420 {
1421 this.cellCountStack.removeLast().toString();
1422 }
1423
1424 if ( this.tableContentWriterStack.isEmpty() )
1425 {
1426 LOGGER.warn( "No table content" );
1427 return;
1428 }
1429
1430 String tableContent = this.tableContentWriterStack.removeLast().toString();
1431
1432 String tableCaption = null;
1433 if ( !this.tableCaptionStack.isEmpty() && this.tableCaptionStack.getLast() != null )
1434 {
1435 tableCaption = this.tableCaptionStack.removeLast();
1436 }
1437
1438 if ( tableCaption != null )
1439 {
1440
1441 StringBuilder sb = new StringBuilder();
1442 sb.append( tableContent, 0, tableContent.indexOf( Markup.GREATER_THAN ) + 1 );
1443 sb.append( tableCaption );
1444 sb.append( tableContent.substring( tableContent.indexOf( Markup.GREATER_THAN ) + 1 ) );
1445
1446 write( sb.toString() );
1447 }
1448 else
1449 {
1450 write( tableContent );
1451 }
1452 }
1453
1454
1455
1456
1457
1458
1459
1460
1461 @Override
1462 public void tableRows( int[] justification, boolean grid )
1463 {
1464 this.tableRows = true;
1465
1466 setCellJustif( justification );
1467
1468 if ( this.tableAttributes == null )
1469 {
1470 this.tableAttributes = new SinkEventAttributeSet( 0 );
1471 }
1472
1473 MutableAttributeSet att = new SinkEventAttributeSet();
1474 if ( !this.tableAttributes.isDefined( Attribute.BORDER.toString() ) )
1475 {
1476 att.addAttribute( Attribute.BORDER, ( grid ? "1" : "0" ) );
1477 }
1478
1479 if ( !this.tableAttributes.isDefined( Attribute.CLASS.toString() ) )
1480 {
1481 att.addAttribute( Attribute.CLASS, "bodyTable" );
1482 }
1483
1484 att.addAttributes( this.tableAttributes );
1485 this.tableAttributes.removeAttributes( this.tableAttributes );
1486
1487 writeStartTag( HtmlMarkup.TABLE, att );
1488
1489 this.cellCountStack.addLast( 0 );
1490 }
1491
1492
1493 @Override
1494 public void tableRows_()
1495 {
1496 this.tableRows = false;
1497 if ( !this.cellJustifStack.isEmpty() )
1498 {
1499 this.cellJustifStack.removeLast();
1500 }
1501 if ( !this.isCellJustifStack.isEmpty() )
1502 {
1503 this.isCellJustifStack.removeLast();
1504 }
1505
1506 this.evenTableRow = true;
1507 }
1508
1509
1510
1511
1512
1513
1514
1515 @Override
1516 public void tableRow()
1517 {
1518
1519 if ( !this.tableRows )
1520 {
1521 tableRows( null, false );
1522 }
1523 tableRow( null );
1524 }
1525
1526
1527
1528
1529
1530
1531
1532 @Override
1533 public void tableRow( SinkEventAttributes attributes )
1534 {
1535 MutableAttributeSet att = new SinkEventAttributeSet();
1536
1537 if ( evenTableRow )
1538 {
1539 att.addAttribute( Attribute.CLASS, "a" );
1540 }
1541 else
1542 {
1543 att.addAttribute( Attribute.CLASS, "b" );
1544 }
1545
1546 att.addAttributes( SinkUtils.filterAttributes(
1547 attributes, SinkUtils.SINK_TR_ATTRIBUTES ) );
1548
1549 writeStartTag( HtmlMarkup.TR, att );
1550
1551 evenTableRow = !evenTableRow;
1552
1553 if ( !this.cellCountStack.isEmpty() )
1554 {
1555 this.cellCountStack.removeLast();
1556 this.cellCountStack.addLast( 0 );
1557 }
1558 }
1559
1560
1561
1562
1563
1564 @Override
1565 public void tableRow_()
1566 {
1567 writeEndTag( HtmlMarkup.TR );
1568 }
1569
1570
1571 @Override
1572 public void tableCell()
1573 {
1574 tableCell( (SinkEventAttributeSet) null );
1575 }
1576
1577
1578 @Override
1579 public void tableHeaderCell()
1580 {
1581 tableHeaderCell( (SinkEventAttributeSet) null );
1582 }
1583
1584
1585 @Override
1586 public void tableCell( SinkEventAttributes attributes )
1587 {
1588 tableCell( false, attributes );
1589 }
1590
1591
1592 @Override
1593 public void tableHeaderCell( SinkEventAttributes attributes )
1594 {
1595 tableCell( true, attributes );
1596 }
1597
1598
1599
1600
1601
1602
1603
1604 private void tableCell( boolean headerRow, MutableAttributeSet attributes )
1605 {
1606 Tag t = ( headerRow ? HtmlMarkup.TH : HtmlMarkup.TD );
1607
1608 if ( !headerRow && cellCountStack != null && !cellCountStack.isEmpty()
1609 && cellJustifStack != null && !cellJustifStack.isEmpty() && getCellJustif() != null )
1610 {
1611 int cellCount = getCellCount();
1612 if ( cellCount < getCellJustif().length )
1613 {
1614 Map<Integer, MutableAttributeSet> hash = new HashMap<>();
1615 hash.put( Sink.JUSTIFY_CENTER, SinkEventAttributeSet.CENTER );
1616 hash.put( Sink.JUSTIFY_LEFT, SinkEventAttributeSet.LEFT );
1617 hash.put( Sink.JUSTIFY_RIGHT, SinkEventAttributeSet.RIGHT );
1618 MutableAttributeSet atts = hash.get( getCellJustif()[cellCount] );
1619
1620 if ( attributes == null )
1621 {
1622 attributes = new SinkEventAttributeSet();
1623 }
1624 if ( atts != null )
1625 {
1626 attributes.addAttributes( atts );
1627 }
1628 }
1629 }
1630
1631 if ( attributes == null )
1632 {
1633 writeStartTag( t, null );
1634 }
1635 else
1636 {
1637 writeStartTag( t,
1638 SinkUtils.filterAttributes( attributes, SinkUtils.SINK_TD_ATTRIBUTES ) );
1639 }
1640 }
1641
1642
1643 @Override
1644 public void tableCell_()
1645 {
1646 tableCell_( false );
1647 }
1648
1649
1650 @Override
1651 public void tableHeaderCell_()
1652 {
1653 tableCell_( true );
1654 }
1655
1656
1657
1658
1659
1660
1661
1662
1663 private void tableCell_( boolean headerRow )
1664 {
1665 Tag t = ( headerRow ? HtmlMarkup.TH : HtmlMarkup.TD );
1666
1667 writeEndTag( t );
1668
1669 if ( !this.isCellJustifStack.isEmpty() && this.isCellJustifStack.getLast().equals( Boolean.TRUE )
1670 && !this.cellCountStack.isEmpty() )
1671 {
1672 int cellCount = Integer.parseInt( this.cellCountStack.removeLast().toString() );
1673 this.cellCountStack.addLast( ++cellCount );
1674 }
1675 }
1676
1677
1678
1679
1680
1681 @Override
1682 public void tableCaption()
1683 {
1684 tableCaption( null );
1685 }
1686
1687
1688
1689
1690
1691 @Override
1692 public void tableCaption( SinkEventAttributes attributes )
1693 {
1694 StringWriter sw = new StringWriter();
1695 this.tableCaptionWriterStack.addLast( sw );
1696 this.tableCaptionXMLWriterStack.addLast( new PrettyPrintXMLWriter( sw ) );
1697
1698
1699 MutableAttributeSet atts = SinkUtils.filterAttributes(
1700 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
1701
1702 writeStartTag( HtmlMarkup.CAPTION, atts );
1703 }
1704
1705
1706
1707
1708
1709 @Override
1710 public void tableCaption_()
1711 {
1712 writeEndTag( HtmlMarkup.CAPTION );
1713
1714 if ( !this.tableCaptionXMLWriterStack.isEmpty() && this.tableCaptionXMLWriterStack.getLast() != null )
1715 {
1716 this.tableCaptionStack.addLast( this.tableCaptionWriterStack.removeLast().toString() );
1717 this.tableCaptionXMLWriterStack.removeLast();
1718 }
1719 }
1720
1721
1722
1723
1724
1725 @Override
1726 public void anchor( String name )
1727 {
1728 anchor( name, null );
1729 }
1730
1731
1732
1733
1734
1735 @Override
1736 public void anchor( String name, SinkEventAttributes attributes )
1737 {
1738 Objects.requireNonNull( name, "name cannot be null" );
1739
1740 if ( headFlag )
1741 {
1742 return;
1743 }
1744
1745 MutableAttributeSet atts = SinkUtils.filterAttributes(
1746 attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
1747
1748 String id = name;
1749
1750 if ( !DoxiaUtils.isValidId( id ) )
1751 {
1752 id = DoxiaUtils.encodeId( name, true );
1753
1754 LOGGER.debug( "Modified invalid anchor name '{}' to '{}'", name, id );
1755 }
1756
1757 MutableAttributeSet att = new SinkEventAttributeSet();
1758 att.addAttribute( Attribute.NAME, id );
1759 att.addAttributes( atts );
1760
1761 writeStartTag( HtmlMarkup.A, att );
1762 }
1763
1764
1765
1766
1767
1768 @Override
1769 public void anchor_()
1770 {
1771 if ( !headFlag )
1772 {
1773 writeEndTag( HtmlMarkup.A );
1774 }
1775 }
1776
1777
1778 @Override
1779 public void link( String name )
1780 {
1781 link( name, null );
1782 }
1783
1784
1785 @Override
1786 public void link( String name, SinkEventAttributes attributes )
1787 {
1788 if ( attributes == null )
1789 {
1790 link( name, null, null );
1791 }
1792 else
1793 {
1794 String target = (String) attributes.getAttribute( Attribute.TARGET.toString() );
1795 MutableAttributeSet atts = SinkUtils.filterAttributes(
1796 attributes, SinkUtils.SINK_LINK_ATTRIBUTES );
1797
1798 link( name, target, atts );
1799 }
1800 }
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812 private void link( String href, String target, MutableAttributeSet attributes )
1813 {
1814 Objects.requireNonNull( href, "href cannot be null" );
1815
1816 if ( headFlag )
1817 {
1818 return;
1819 }
1820
1821 MutableAttributeSet att = new SinkEventAttributeSet();
1822
1823 if ( DoxiaUtils.isExternalLink( href ) )
1824 {
1825 att.addAttribute( Attribute.CLASS, "externalLink" );
1826 }
1827
1828 att.addAttribute( Attribute.HREF, HtmlTools.escapeHTML( href ) );
1829
1830 if ( target != null )
1831 {
1832 att.addAttribute( Attribute.TARGET, target );
1833 }
1834
1835 if ( attributes != null )
1836 {
1837 attributes.removeAttribute( Attribute.HREF.toString() );
1838 attributes.removeAttribute( Attribute.TARGET.toString() );
1839 att.addAttributes( attributes );
1840 }
1841
1842 writeStartTag( HtmlMarkup.A, att );
1843 }
1844
1845
1846
1847
1848
1849 @Override
1850 public void link_()
1851 {
1852 if ( !headFlag )
1853 {
1854 writeEndTag( HtmlMarkup.A );
1855 }
1856 }
1857
1858
1859 @Override
1860 public void inline()
1861 {
1862 inline( null );
1863 }
1864
1865 private void inlineSemantics( SinkEventAttributes attributes, String semantic,
1866 List<Tag> tags, Tag tag )
1867 {
1868 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, semantic ) )
1869 {
1870 SinkEventAttributes attributesNoSemantics = ( SinkEventAttributes ) attributes.copyAttributes();
1871 attributesNoSemantics.removeAttribute( SinkEventAttributes.SEMANTICS );
1872 writeStartTag( tag, attributesNoSemantics );
1873 tags.add( 0, tag );
1874 }
1875 }
1876
1877
1878 @Override
1879 public void inline( SinkEventAttributes attributes )
1880 {
1881 if ( !headFlag )
1882 {
1883 List<Tag> tags = new ArrayList<>();
1884
1885 if ( attributes != null )
1886 {
1887 inlineSemantics( attributes, "emphasis", tags, HtmlMarkup.EM );
1888 inlineSemantics( attributes, "strong", tags, HtmlMarkup.STRONG );
1889 inlineSemantics( attributes, "small", tags, HtmlMarkup.SMALL );
1890 inlineSemantics( attributes, "line-through", tags, HtmlMarkup.S );
1891 inlineSemantics( attributes, "citation", tags, HtmlMarkup.CITE );
1892 inlineSemantics( attributes, "quote", tags, HtmlMarkup.Q );
1893 inlineSemantics( attributes, "definition", tags, HtmlMarkup.DFN );
1894 inlineSemantics( attributes, "abbreviation", tags, HtmlMarkup.ABBR );
1895 inlineSemantics( attributes, "italic", tags, HtmlMarkup.I );
1896 inlineSemantics( attributes, "bold", tags, HtmlMarkup.B );
1897 inlineSemantics( attributes, "code", tags, HtmlMarkup.CODE );
1898 inlineSemantics( attributes, "variable", tags, HtmlMarkup.VAR );
1899 inlineSemantics( attributes, "sample", tags, HtmlMarkup.SAMP );
1900 inlineSemantics( attributes, "keyboard", tags, HtmlMarkup.KBD );
1901 inlineSemantics( attributes, "superscript", tags, HtmlMarkup.SUP );
1902 inlineSemantics( attributes, "subscript", tags, HtmlMarkup.SUB );
1903 inlineSemantics( attributes, "annotation", tags, HtmlMarkup.U );
1904 inlineSemantics( attributes, "highlight", tags, HtmlMarkup.MARK );
1905 inlineSemantics( attributes, "ruby", tags, HtmlMarkup.RUBY );
1906 inlineSemantics( attributes, "rubyBase", tags, HtmlMarkup.RB );
1907 inlineSemantics( attributes, "rubyText", tags, HtmlMarkup.RT );
1908 inlineSemantics( attributes, "rubyTextContainer", tags, HtmlMarkup.RTC );
1909 inlineSemantics( attributes, "rubyParentheses", tags, HtmlMarkup.RP );
1910 inlineSemantics( attributes, "bidirectionalIsolation", tags, HtmlMarkup.BDI );
1911 inlineSemantics( attributes, "bidirectionalOverride", tags, HtmlMarkup.BDO );
1912 inlineSemantics( attributes, "phrase", tags, HtmlMarkup.SPAN );
1913 inlineSemantics( attributes, "insert", tags, HtmlMarkup.INS );
1914 inlineSemantics( attributes, "delete", tags, HtmlMarkup.DEL );
1915 }
1916
1917 inlineStack.push( tags );
1918 }
1919 }
1920
1921
1922 @Override
1923 public void inline_()
1924 {
1925 if ( !headFlag )
1926 {
1927 for ( Tag tag: inlineStack.pop() )
1928 {
1929 writeEndTag( tag );
1930 }
1931 }
1932 }
1933
1934
1935
1936
1937
1938 @Override
1939 public void italic()
1940 {
1941 inline( SinkEventAttributeSet.Semantics.ITALIC );
1942 }
1943
1944
1945
1946
1947
1948 @Override
1949 public void italic_()
1950 {
1951 inline_();
1952 }
1953
1954
1955
1956
1957
1958 @Override
1959 public void bold()
1960 {
1961 inline( SinkEventAttributeSet.Semantics.BOLD );
1962 }
1963
1964
1965
1966
1967
1968 @Override
1969 public void bold_()
1970 {
1971 inline_();
1972 }
1973
1974
1975
1976
1977
1978 @Override
1979 public void monospaced()
1980 {
1981 inline( SinkEventAttributeSet.Semantics.CODE );
1982 }
1983
1984
1985
1986
1987
1988 @Override
1989 public void monospaced_()
1990 {
1991 inline_();
1992 }
1993
1994
1995
1996
1997
1998 @Override
1999 public void lineBreak()
2000 {
2001 lineBreak( null );
2002 }
2003
2004
2005
2006
2007
2008 @Override
2009 public void lineBreak( SinkEventAttributes attributes )
2010 {
2011 if ( headFlag || isVerbatimFlag() )
2012 {
2013 getTextBuffer().append( EOL );
2014 }
2015 else
2016 {
2017 MutableAttributeSet atts = SinkUtils.filterAttributes(
2018 attributes, SinkUtils.SINK_BR_ATTRIBUTES );
2019
2020 writeSimpleTag( HtmlMarkup.BR, atts );
2021 }
2022 }
2023
2024
2025 @Override
2026 public void lineBreakOpportunity()
2027 {
2028 lineBreakOpportunity( null );
2029 }
2030
2031
2032 @Override
2033 public void lineBreakOpportunity( SinkEventAttributes attributes )
2034 {
2035 if ( !headFlag && !isVerbatimFlag() )
2036 {
2037 MutableAttributeSet atts = SinkUtils.filterAttributes(
2038 attributes, SinkUtils.SINK_BR_ATTRIBUTES );
2039
2040 writeSimpleTag( HtmlMarkup.WBR, atts );
2041 }
2042 }
2043
2044
2045 @Override
2046 public void pageBreak()
2047 {
2048 comment( " PB " );
2049 }
2050
2051
2052 @Override
2053 public void nonBreakingSpace()
2054 {
2055 if ( headFlag )
2056 {
2057 getTextBuffer().append( ' ' );
2058 }
2059 else
2060 {
2061 write( " " );
2062 }
2063 }
2064
2065
2066 @Override
2067 public void text( String text )
2068 {
2069 if ( headFlag )
2070 {
2071 getTextBuffer().append( text );
2072 }
2073 else if ( verbatimFlag )
2074 {
2075 verbatimContent( text );
2076 }
2077 else
2078 {
2079 content( text );
2080 }
2081 }
2082
2083
2084 @Override
2085 public void text( String text, SinkEventAttributes attributes )
2086 {
2087 text( text );
2088 }
2089
2090
2091 @Override
2092 public void rawText( String text )
2093 {
2094 if ( headFlag )
2095 {
2096 getTextBuffer().append( text );
2097 }
2098 else
2099 {
2100 write( text );
2101 }
2102 }
2103
2104
2105 @Override
2106 public void comment( String comment )
2107 {
2108 if ( comment != null )
2109 {
2110 final String originalComment = comment;
2111
2112
2113 while ( comment.contains( "--" ) )
2114 {
2115 comment = comment.replace( "--", "- -" );
2116 }
2117
2118 if ( comment.endsWith( "-" ) )
2119 {
2120 comment += " ";
2121 }
2122
2123 if ( !originalComment.equals( comment ) )
2124 {
2125 LOGGER.warn( "Modified invalid comment '{}' to '{}'", originalComment, comment );
2126 }
2127
2128 final StringBuilder buffer = new StringBuilder( comment.length() + 7 );
2129
2130 buffer.append( LESS_THAN ).append( BANG ).append( MINUS ).append( MINUS );
2131 buffer.append( comment );
2132 buffer.append( MINUS ).append( MINUS ).append( GREATER_THAN );
2133
2134 write( buffer.toString() );
2135 }
2136 }
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179 @Override
2180 public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes )
2181 {
2182 if ( requiredParams == null || !( requiredParams[0] instanceof Integer ) )
2183 {
2184 LOGGER.warn( "No type information for unknown event '{}', ignoring!", name );
2185
2186 return;
2187 }
2188
2189 int tagType = (Integer) requiredParams[0];
2190
2191 if ( tagType == ENTITY_TYPE )
2192 {
2193 rawText( name );
2194
2195 return;
2196 }
2197
2198 if ( tagType == CDATA_TYPE )
2199 {
2200 rawText( EOL + "//<![CDATA[" + requiredParams[1] + "]]>" + EOL );
2201
2202 return;
2203 }
2204
2205 Tag tag = HtmlTools.getHtmlTag( name );
2206
2207 if ( tag == null )
2208 {
2209 LOGGER.warn( "No HTML tag found for unknown event '{}', ignoring!", name );
2210 }
2211 else
2212 {
2213 if ( tagType == TAG_TYPE_SIMPLE )
2214 {
2215 writeSimpleTag( tag, escapeAttributeValues( attributes ) );
2216 }
2217 else if ( tagType == TAG_TYPE_START )
2218 {
2219 writeStartTag( tag, escapeAttributeValues( attributes ) );
2220 }
2221 else if ( tagType == TAG_TYPE_END )
2222 {
2223 writeEndTag( tag );
2224 }
2225 else
2226 {
2227 LOGGER.warn( "No type information for unknown event '{}', ignoring!", name );
2228 }
2229 }
2230 }
2231
2232 private SinkEventAttributes escapeAttributeValues( SinkEventAttributes attributes )
2233 {
2234 SinkEventAttributeSet set = new SinkEventAttributeSet( attributes.getAttributeCount() );
2235
2236 Enumeration<?> names = attributes.getAttributeNames();
2237
2238 while ( names.hasMoreElements() )
2239 {
2240 Object name = names.nextElement();
2241
2242 set.addAttribute( name, escapeHTML( attributes.getAttribute( name ).toString() ) );
2243 }
2244
2245 return set;
2246 }
2247
2248
2249 @Override
2250 public void flush()
2251 {
2252 writer.flush();
2253 }
2254
2255
2256 @Override
2257 public void close()
2258 {
2259 writer.close();
2260
2261 init();
2262 }
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273 protected void content( String text )
2274 {
2275
2276 String txt = escapeHTML( text );
2277 txt = StringUtils.replace( txt, "&#", "&#" );
2278 write( txt );
2279 }
2280
2281
2282
2283
2284
2285
2286 protected void verbatimContent( String text )
2287 {
2288 write( escapeHTML( text ) );
2289 }
2290
2291
2292
2293
2294
2295
2296
2297
2298 protected static String escapeHTML( String text )
2299 {
2300 return HtmlTools.escapeHTML( text, false );
2301 }
2302
2303
2304
2305
2306
2307
2308
2309
2310 protected static String encodeURL( String text )
2311 {
2312 return HtmlTools.encodeURL( text );
2313 }
2314
2315
2316 protected void write( String text )
2317 {
2318 if ( !this.tableCaptionXMLWriterStack.isEmpty() && this.tableCaptionXMLWriterStack.getLast() != null )
2319 {
2320 this.tableCaptionXMLWriterStack.getLast().writeMarkup( unifyEOLs( text ) );
2321 }
2322 else if ( !this.tableContentWriterStack.isEmpty() && this.tableContentWriterStack.getLast() != null )
2323 {
2324 this.tableContentWriterStack.getLast().write( unifyEOLs( text ) );
2325 }
2326 else
2327 {
2328 writer.write( unifyEOLs( text ) );
2329 }
2330 }
2331
2332
2333 @Override
2334 protected void writeStartTag( Tag t, MutableAttributeSet att, boolean isSimpleTag )
2335 {
2336 if ( this.tableCaptionXMLWriterStack.isEmpty() )
2337 {
2338 super.writeStartTag ( t, att, isSimpleTag );
2339 }
2340 else
2341 {
2342 String tag = ( getNameSpace() != null ? getNameSpace() + ":" : "" ) + t.toString();
2343 this.tableCaptionXMLWriterStack.getLast().startElement( tag );
2344
2345 if ( att != null )
2346 {
2347 Enumeration<?> names = att.getAttributeNames();
2348 while ( names.hasMoreElements() )
2349 {
2350 Object key = names.nextElement();
2351 Object value = att.getAttribute( key );
2352
2353 this.tableCaptionXMLWriterStack.getLast().addAttribute( key.toString(), value.toString() );
2354 }
2355 }
2356
2357 if ( isSimpleTag )
2358 {
2359 this.tableCaptionXMLWriterStack.getLast().endElement();
2360 }
2361 }
2362 }
2363
2364
2365 @Override
2366 protected void writeEndTag( Tag t )
2367 {
2368 if ( this.tableCaptionXMLWriterStack.isEmpty() )
2369 {
2370 super.writeEndTag( t );
2371 }
2372 else
2373 {
2374 this.tableCaptionXMLWriterStack.getLast().endElement();
2375 }
2376 }
2377 }