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