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