1 package org.apache.maven.archetype.common.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 import org.codehaus.plexus.util.StringUtils;
56 import org.jdom.Attribute;
57 import org.jdom.CDATA;
58 import org.jdom.Comment;
59 import org.jdom.DocType;
60 import org.jdom.Document;
61 import org.jdom.Element;
62 import org.jdom.EntityRef;
63 import org.jdom.Namespace;
64 import org.jdom.ProcessingInstruction;
65 import org.jdom.Text;
66 import org.jdom.output.EscapeStrategy;
67
68 import javax.xml.transform.Result;
69 import java.io.BufferedOutputStream;
70 import java.io.BufferedWriter;
71 import java.io.IOException;
72 import java.io.OutputStream;
73 import java.io.OutputStreamWriter;
74 import java.io.StringWriter;
75 import java.io.Writer;
76 import java.util.List;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 public class XMLOutputter
130 implements Cloneable
131 {
132
133 private Format userFormat = Format.getRawFormat();
134
135
136 protected static final Format preserveFormat = Format.getRawFormat();
137
138
139 protected Format currentFormat = userFormat;
140
141
142
143
144
145 private boolean escapeOutput = true;
146
147
148
149
150
151
152
153
154 public XMLOutputter()
155 {
156 }
157
158
159
160
161
162
163 public XMLOutputter( Format format )
164 {
165 userFormat = (Format) format.clone();
166 currentFormat = userFormat;
167 }
168
169
170
171
172
173
174
175
176
177 public XMLOutputter( XMLOutputter that )
178 {
179 this.userFormat = (Format) that.userFormat.clone();
180 currentFormat = userFormat;
181 }
182
183
184
185
186
187
188
189
190
191
192 public void setFormat( Format newFormat )
193 {
194 this.userFormat = (Format) newFormat.clone();
195 this.currentFormat = userFormat;
196 }
197
198
199
200
201
202 public Format getFormat()
203 {
204 return (Format) userFormat.clone();
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218
219 public void output( Document doc, OutputStream out )
220 throws IOException
221 {
222 Writer writer = makeWriter( out );
223 output( doc, writer );
224 }
225
226
227
228
229
230
231
232 public void output( DocType doctype, OutputStream out )
233 throws IOException
234 {
235 Writer writer = makeWriter( out );
236 output( doctype, writer );
237 }
238
239
240
241
242
243
244
245
246
247 public void output( Element element, OutputStream out )
248 throws IOException
249 {
250 Writer writer = makeWriter( out );
251 output( element, writer );
252 }
253
254
255
256
257
258
259
260
261
262
263
264 public void outputElementContent( Element element, OutputStream out )
265 throws IOException
266 {
267 Writer writer = makeWriter( out );
268 outputElementContent( element, writer );
269 }
270
271
272
273
274
275
276
277
278
279
280 public void output( List<?> list, OutputStream out )
281 throws IOException
282 {
283 Writer writer = makeWriter( out );
284 output( list, writer );
285 }
286
287
288
289
290
291
292
293 public void output( CDATA cdata, OutputStream out )
294 throws IOException
295 {
296 Writer writer = makeWriter( out );
297 output( cdata, writer );
298 }
299
300
301
302
303
304
305
306
307 public void output( Text text, OutputStream out )
308 throws IOException
309 {
310 Writer writer = makeWriter( out );
311 output( text, writer );
312 }
313
314
315
316
317
318
319
320 public void output( Comment comment, OutputStream out )
321 throws IOException
322 {
323 Writer writer = makeWriter( out );
324 output( comment, writer );
325 }
326
327
328
329
330
331
332
333 public void output( ProcessingInstruction pi, OutputStream out )
334 throws IOException
335 {
336 Writer writer = makeWriter( out );
337 output( pi, writer );
338 }
339
340
341
342
343
344
345
346 public void output( EntityRef entity, OutputStream out )
347 throws IOException
348 {
349 Writer writer = makeWriter( out );
350 output( entity, writer );
351 }
352
353
354
355
356
357 private Writer makeWriter( OutputStream out )
358 throws java.io.UnsupportedEncodingException
359 {
360 return makeWriter( out, userFormat.encoding );
361 }
362
363
364 private static Writer makeWriter( OutputStream out, String enc )
365 throws java.io.UnsupportedEncodingException
366 {
367
368
369 if ( "UTF-8".equals( enc ) )
370 {
371 enc = "UTF8";
372 }
373
374 Writer writer = new BufferedWriter( ( new OutputStreamWriter( new BufferedOutputStream( out ), enc ) ) );
375 return writer;
376 }
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393 public void output( Document doc, Writer out )
394 throws IOException
395 {
396
397 printDeclaration( out, doc, userFormat.encoding );
398
399
400
401
402 List<?> content = doc.getContent();
403 int size = content.size();
404 for ( int i = 0; i < size; i++ )
405 {
406 Object obj = content.get( i );
407
408 if ( obj instanceof Element )
409 {
410 printElement( out, doc.getRootElement(), 0, createNamespaceStack() );
411 }
412 else if ( obj instanceof Comment )
413 {
414 printComment( out, (Comment) obj );
415 }
416 else if ( obj instanceof ProcessingInstruction )
417 {
418 printProcessingInstruction( out, (ProcessingInstruction) obj );
419 }
420 else if ( obj instanceof DocType )
421 {
422 printDocType( out, doc.getDocType() );
423
424
425 out.write( currentFormat.lineSeparator );
426 }
427 else
428 {
429
430
431 }
432
433 newline( out );
434 indent( out, 0 );
435 }
436
437
438
439 out.write( currentFormat.lineSeparator );
440 }
441
442
443
444
445
446
447
448 public void output( DocType doctype, Writer out )
449 throws IOException
450 {
451 printDocType( out, doctype );
452 }
453
454
455
456
457
458
459
460
461
462 public void output( Element element, Writer out )
463 throws IOException
464 {
465
466
467 printElement( out, element, 0, createNamespaceStack() );
468 }
469
470
471
472
473
474
475
476
477
478
479
480 public void outputElementContent( Element element, Writer out )
481 throws IOException
482 {
483 List<?> content = element.getContent();
484 printContentRange( out, content, 0, content.size(),
485 0, createNamespaceStack() );
486 }
487
488
489
490
491
492
493
494
495
496
497 public void output( List<?> list, Writer out )
498 throws IOException
499 {
500 printContentRange( out, list, 0, list.size(), 0, createNamespaceStack() );
501 }
502
503
504
505
506
507
508
509 public void output( CDATA cdata, Writer out )
510 throws IOException
511 {
512 printCDATA( out, cdata );
513 }
514
515
516
517
518
519
520
521
522 public void output( Text text, Writer out )
523 throws IOException
524 {
525 printText( out, text );
526 }
527
528
529
530
531
532
533
534 public void output( Comment comment, Writer out )
535 throws IOException
536 {
537 printComment( out, comment );
538 }
539
540
541
542
543
544
545
546 public void output( ProcessingInstruction pi, Writer out )
547 throws IOException
548 {
549 boolean currentEscapingPolicy = currentFormat.ignoreTrAXEscapingPIs;
550
551
552 currentFormat.setIgnoreTrAXEscapingPIs( true );
553 printProcessingInstruction( out, pi );
554 currentFormat.setIgnoreTrAXEscapingPIs( currentEscapingPolicy );
555 }
556
557
558
559
560
561
562
563 public void output( EntityRef entity, Writer out )
564 throws IOException
565 {
566 printEntityRef( out, entity );
567 }
568
569
570
571
572
573
574
575
576
577
578
579 public String outputString( Document doc )
580 {
581 StringWriter out = new StringWriter();
582 try
583 {
584 output( doc, out );
585 }
586 catch ( IOException e )
587 {
588 }
589 return out.toString();
590 }
591
592
593
594
595
596
597
598
599 public String outputString( DocType doctype )
600 {
601 StringWriter out = new StringWriter();
602 try
603 {
604 output( doctype, out );
605 }
606 catch ( IOException e )
607 {
608 }
609 return out.toString();
610 }
611
612
613
614
615
616
617
618
619 public String outputString( Element element )
620 {
621 StringWriter out = new StringWriter();
622 try
623 {
624 output( element, out );
625 }
626 catch ( IOException e )
627 {
628 }
629 return out.toString();
630 }
631
632
633
634
635
636
637
638 public String outputString( List<?> list )
639 {
640 StringWriter out = new StringWriter();
641 try
642 {
643 output( list, out );
644 }
645 catch ( IOException e )
646 {
647 }
648 return out.toString();
649 }
650
651
652
653
654
655
656
657
658 public String outputString( CDATA cdata )
659 {
660 StringWriter out = new StringWriter();
661 try
662 {
663 output( cdata, out );
664 }
665 catch ( IOException e )
666 {
667 }
668 return out.toString();
669 }
670
671
672
673
674
675
676
677
678 public String outputString( Text text )
679 {
680 StringWriter out = new StringWriter();
681 try
682 {
683 output( text, out );
684 }
685 catch ( IOException e )
686 {
687 }
688 return out.toString();
689 }
690
691
692
693
694
695
696
697
698
699 public String outputString( Comment comment )
700 {
701 StringWriter out = new StringWriter();
702 try
703 {
704 output( comment, out );
705 }
706 catch ( IOException e )
707 {
708 }
709 return out.toString();
710 }
711
712
713
714
715
716
717
718
719 public String outputString( ProcessingInstruction pi )
720 {
721 StringWriter out = new StringWriter();
722 try
723 {
724 output( pi, out );
725 }
726 catch ( IOException e )
727 {
728 }
729 return out.toString();
730 }
731
732
733
734
735
736
737
738
739 public String outputString( EntityRef entity )
740 {
741 StringWriter out = new StringWriter();
742 try
743 {
744 output( entity, out );
745 }
746 catch ( IOException e )
747 {
748 }
749 return out.toString();
750 }
751
752
753
754
755
756
757
758
759
760
761
762
763 protected void printDeclaration( Writer out, Document doc, String encoding )
764 throws IOException
765 {
766
767
768 if ( !userFormat.omitDeclaration )
769 {
770
771 out.write( "<?xml version=\"1.0\"" );
772 if ( !userFormat.omitEncoding )
773 {
774 out.write( " encoding=\"" + encoding + "\"" );
775 }
776 out.write( "?>" );
777
778
779
780
781 out.write( currentFormat.lineSeparator );
782 }
783 }
784
785
786
787
788
789
790
791 protected void printDocType( Writer out, DocType docType )
792 throws IOException
793 {
794
795 String publicID = docType.getPublicID();
796 String systemID = docType.getSystemID();
797 String internalSubset = docType.getInternalSubset();
798 boolean hasPublic = false;
799
800 out.write( "<!DOCTYPE " );
801 out.write( docType.getElementName() );
802 if ( publicID != null )
803 {
804 out.write( " PUBLIC \"" );
805 out.write( publicID );
806 out.write( "\"" );
807 hasPublic = true;
808 }
809 if ( systemID != null )
810 {
811 if ( !hasPublic )
812 {
813 out.write( " SYSTEM" );
814 }
815 out.write( " \"" );
816 out.write( systemID );
817 out.write( "\"" );
818 }
819 if ( ( internalSubset != null ) && ( !internalSubset.equals( "" ) ) )
820 {
821 out.write( " [" );
822 out.write( currentFormat.lineSeparator );
823 out.write( docType.getInternalSubset() );
824 out.write( "]" );
825 }
826 out.write( ">" );
827 }
828
829
830
831
832
833
834
835 protected void printComment( Writer out, Comment comment )
836 throws IOException
837 {
838 out.write( "<!--" );
839 out.write( StringUtils.unifyLineSeparators( comment.getText(), currentFormat.lineSeparator ) );
840 out.write( "-->" );
841 }
842
843
844
845
846
847
848
849 protected void printProcessingInstruction( Writer out, ProcessingInstruction pi )
850 throws IOException
851 {
852 String target = pi.getTarget();
853 boolean piProcessed = false;
854
855 if ( currentFormat.ignoreTrAXEscapingPIs == false )
856 {
857 if ( target.equals( Result.PI_DISABLE_OUTPUT_ESCAPING ) )
858 {
859 escapeOutput = false;
860 piProcessed = true;
861 }
862 else if ( target.equals( Result.PI_ENABLE_OUTPUT_ESCAPING ) )
863 {
864 escapeOutput = true;
865 piProcessed = true;
866 }
867 }
868 if ( piProcessed == false )
869 {
870 String rawData = pi.getData();
871
872
873 if ( !"".equals( rawData ) )
874 {
875 out.write( "<?" );
876 out.write( target );
877 out.write( " " );
878 out.write( rawData );
879 out.write( "?>" );
880 }
881 else
882 {
883 out.write( "<?" );
884 out.write( target );
885 out.write( "?>" );
886 }
887 }
888 }
889
890
891
892
893
894
895
896
897
898
899 protected void printEntityRef( Writer out, EntityRef entity )
900 throws IOException
901 {
902 out.write( "&" );
903 out.write( entity.getName() );
904 out.write( ";" );
905 }
906
907
908
909
910
911
912
913 protected void printCDATA( Writer out, CDATA cdata )
914 throws IOException
915 {
916 String str =
917 ( currentFormat.mode == Format.TextMode.NORMALIZE ) ? cdata.getTextNormalize()
918 : ( ( currentFormat.mode == Format.TextMode.TRIM ) ? cdata.getText().trim()
919 : cdata.getText() );
920 out.write( "<![CDATA[" );
921 out.write( str );
922 out.write( "]]>" );
923 }
924
925
926
927
928
929
930
931 protected void printText( Writer out, Text text )
932 throws IOException
933 {
934 String str =
935 ( currentFormat.mode == Format.TextMode.NORMALIZE ) ? text.getTextNormalize()
936 : ( ( currentFormat.mode == Format.TextMode.TRIM ) ? text.getText().trim() : text.getText() );
937 out.write( escapeElementEntities( str ) );
938 }
939
940
941
942
943
944 private void printString( Writer out, String str )
945 throws IOException
946 {
947 if ( currentFormat.mode == Format.TextMode.NORMALIZE )
948 {
949 str = Text.normalizeString( str );
950 }
951 else if ( currentFormat.mode == Format.TextMode.TRIM )
952 {
953 str = str.trim();
954 }
955 out.write( escapeElementEntities( str ) );
956 }
957
958
959
960
961
962
963
964
965
966
967
968 protected void printElement( Writer out, Element element, int level, NamespaceStack namespaces )
969 throws IOException
970 {
971
972 List<?> attributes = element.getAttributes();
973 List<?> content = element.getContent();
974
975
976 String space = null;
977 if ( attributes != null )
978 {
979 space = element.getAttributeValue( "space", Namespace.XML_NAMESPACE );
980 }
981
982 Format previousFormat = currentFormat;
983
984 if ( "default".equals( space ) )
985 {
986 currentFormat = userFormat;
987 }
988 else if ( "preserve".equals( space ) )
989 {
990 currentFormat = preserveFormat;
991 }
992
993
994
995 out.write( "<" );
996 printQualifiedName( out, element );
997
998
999 int previouslyDeclaredNamespaces = namespaces.size();
1000
1001
1002 printElementNamespace( out, element, namespaces );
1003
1004
1005 printAdditionalNamespaces( out, element, namespaces );
1006
1007
1008 if ( attributes != null )
1009 {
1010 printAttributes( out, attributes, element, namespaces );
1011 }
1012
1013
1014
1015
1016
1017
1018 int start = skipLeadingWhite( content, 0 );
1019 int size = content.size();
1020 if ( start >= size )
1021 {
1022
1023 if ( currentFormat.expandEmptyElements )
1024 {
1025 out.write( "></" );
1026 printQualifiedName( out, element );
1027 out.write( ">" );
1028 }
1029 else
1030 {
1031 out.write( " />" );
1032 }
1033 }
1034 else
1035 {
1036 out.write( ">" );
1037
1038
1039
1040
1041
1042 if ( nextNonText( content, start ) < size )
1043 {
1044
1045 newline( out );
1046 printContentRange( out, content, start, size,
1047 level + 1, namespaces );
1048 newline( out );
1049 indent( out, level );
1050 }
1051 else
1052 {
1053
1054 printTextRange( out, content, start, size );
1055 }
1056 out.write( "</" );
1057 printQualifiedName( out, element );
1058 out.write( ">" );
1059 }
1060
1061
1062 while ( namespaces.size() > previouslyDeclaredNamespaces )
1063 {
1064 namespaces.pop();
1065 }
1066
1067
1068 currentFormat = previousFormat;
1069 }
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084 private void printContentRange( Writer out, List<?> content, int start, int end, int level, NamespaceStack namespaces )
1085 throws IOException
1086 {
1087 boolean firstNode;
1088 Object next;
1089 int first, index;
1090
1091 index = start;
1092 while ( index < end )
1093 {
1094 firstNode = ( index == start ) ? true : false;
1095 next = content.get( index );
1096
1097
1098
1099
1100 if ( ( next instanceof Text ) || ( next instanceof EntityRef ) )
1101 {
1102 first = skipLeadingWhite( content, index );
1103
1104 index = nextNonText( content, first );
1105
1106
1107 if ( first < index )
1108 {
1109 if ( !firstNode )
1110 {
1111 newline( out );
1112 }
1113 indent( out, level );
1114 printTextRange( out, content, first, index );
1115 }
1116 continue;
1117 }
1118
1119
1120
1121
1122 if ( !firstNode )
1123 {
1124 newline( out );
1125 }
1126
1127 indent( out, level );
1128
1129 if ( next instanceof Comment )
1130 {
1131 printComment( out, (Comment) next );
1132 }
1133 else if ( next instanceof Element )
1134 {
1135 printElement( out, (Element) next, level, namespaces );
1136 }
1137 else if ( next instanceof ProcessingInstruction )
1138 {
1139 printProcessingInstruction( out, (ProcessingInstruction) next );
1140 }
1141 else
1142 {
1143
1144
1145
1146 }
1147
1148 index++;
1149 }
1150 }
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162 private void printTextRange( Writer out, List<?> content, int start, int end )
1163 throws IOException
1164 {
1165 String previous;
1166 Object node;
1167 String next;
1168
1169 previous = null;
1170
1171
1172 start = skipLeadingWhite( content, start );
1173
1174 int size = content.size();
1175 if ( start < size )
1176 {
1177
1178 end = skipTrailingWhite( content, end );
1179
1180 for ( int i = start; i < end; i++ )
1181 {
1182 node = content.get( i );
1183
1184
1185
1186 if ( node instanceof CDATA )
1187 {
1188 next = "<![CDATA[" + ( (CDATA) node ).getValue() + "]]>";
1189 }
1190 else if ( node instanceof Text )
1191 {
1192 next = ( (Text) node ).getText();
1193 }
1194 else if ( node instanceof EntityRef )
1195 {
1196 next = "&" + ( (EntityRef) node ).getValue() + ";";
1197 }
1198 else
1199 {
1200 throw new IllegalStateException( "Should see only CDATA, Text, or EntityRef" );
1201 }
1202
1203
1204 if ( next == null || "".equals( next ) )
1205 {
1206 continue;
1207 }
1208
1209
1210
1211 if ( previous != null )
1212 {
1213 if ( currentFormat.mode == Format.TextMode.NORMALIZE
1214 || currentFormat.mode == Format.TextMode.TRIM )
1215 {
1216 if ( ( endsWithWhite( previous ) )
1217 || ( startsWithWhite( next ) ) )
1218 {
1219 out.write( " " );
1220 }
1221 }
1222 }
1223
1224
1225 if ( node instanceof CDATA )
1226 {
1227 printCDATA( out, (CDATA) node );
1228 }
1229 else if ( node instanceof EntityRef )
1230 {
1231 printEntityRef( out, (EntityRef) node );
1232 }
1233 else
1234 {
1235 printString( out, next );
1236 }
1237
1238 previous = next;
1239 }
1240 }
1241 }
1242
1243
1244
1245
1246
1247
1248
1249
1250 private void printNamespace( Writer out, Namespace ns, NamespaceStack namespaces )
1251 throws IOException
1252 {
1253 String prefix = ns.getPrefix();
1254 String uri = ns.getURI();
1255
1256
1257 if ( uri.equals( namespaces.getURI( prefix ) ) )
1258 {
1259 return;
1260 }
1261
1262 out.write( " xmlns" );
1263 if ( !prefix.equals( "" ) )
1264 {
1265 out.write( ":" );
1266 out.write( prefix );
1267 }
1268 out.write( "=\"" );
1269 out.write( uri );
1270 out.write( "\"" );
1271 namespaces.push( ns );
1272 }
1273
1274
1275
1276
1277
1278
1279
1280 protected void printAttributes( Writer out, List<?> attributes, Element parent, NamespaceStack namespaces )
1281 throws IOException
1282 {
1283
1284
1285
1286
1287
1288
1289 for ( int i = 0; i < attributes.size(); i++ )
1290 {
1291 Attribute attribute = (Attribute) attributes.get( i );
1292 Namespace ns = attribute.getNamespace();
1293 if ( ( ns != Namespace.NO_NAMESPACE ) && ( ns != Namespace.XML_NAMESPACE ) )
1294 {
1295 printNamespace( out, ns, namespaces );
1296 }
1297
1298 out.write( " " );
1299 printQualifiedName( out, attribute );
1300 out.write( "=" );
1301
1302 out.write( "\"" );
1303 out.write( escapeAttributeEntities( attribute.getValue() ) );
1304 out.write( "\"" );
1305 }
1306 }
1307
1308 private void printElementNamespace( Writer out, Element element, NamespaceStack namespaces )
1309 throws IOException
1310 {
1311
1312
1313
1314
1315 Namespace ns = element.getNamespace();
1316 if ( ns == Namespace.XML_NAMESPACE )
1317 {
1318 return;
1319 }
1320 if ( !( ( ns == Namespace.NO_NAMESPACE ) && ( namespaces.getURI( "" ) == null ) ) )
1321 {
1322 printNamespace( out, ns, namespaces );
1323 }
1324 }
1325
1326 private void printAdditionalNamespaces( Writer out, Element element, NamespaceStack namespaces )
1327 throws IOException
1328 {
1329 List<?> list = element.getAdditionalNamespaces();
1330 if ( list != null )
1331 {
1332 for ( int i = 0; i < list.size(); i++ )
1333 {
1334 Namespace additional = (Namespace) list.get( i );
1335 printNamespace( out, additional, namespaces );
1336 }
1337 }
1338 }
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349 private void newline( Writer out )
1350 throws IOException
1351 {
1352 if ( currentFormat.indent != null )
1353 {
1354 out.write( currentFormat.lineSeparator );
1355 }
1356 }
1357
1358
1359
1360
1361
1362
1363
1364
1365 private void indent( Writer out, int level )
1366 throws IOException
1367 {
1368 if ( currentFormat.indent == null || currentFormat.indent.equals( "" ) )
1369 {
1370 return;
1371 }
1372
1373 for ( int i = 0; i < level; i++ )
1374 {
1375 out.write( currentFormat.indent );
1376 }
1377 }
1378
1379
1380
1381
1382
1383 private int skipLeadingWhite( List<?> content, int start )
1384 {
1385 if ( start < 0 )
1386 {
1387 start = 0;
1388 }
1389
1390 int index = start;
1391 int size = content.size();
1392 if ( currentFormat.mode == Format.TextMode.TRIM_FULL_WHITE
1393 || currentFormat.mode == Format.TextMode.NORMALIZE
1394 || currentFormat.mode == Format.TextMode.TRIM )
1395 {
1396 while ( index < size )
1397 {
1398 if ( !isAllWhitespace( content.get( index ) ) )
1399 {
1400 return index;
1401 }
1402 index++;
1403 }
1404 }
1405 return index;
1406 }
1407
1408
1409
1410
1411
1412 private int skipTrailingWhite( List<?> content, int start )
1413 {
1414 int size = content.size();
1415 if ( start > size )
1416 {
1417 start = size;
1418 }
1419
1420 int index = start;
1421 if ( currentFormat.mode == Format.TextMode.TRIM_FULL_WHITE
1422 || currentFormat.mode == Format.TextMode.NORMALIZE
1423 || currentFormat.mode == Format.TextMode.TRIM )
1424 {
1425 while ( index >= 0 )
1426 {
1427 if ( !isAllWhitespace( content.get( index - 1 ) ) )
1428 {
1429 break;
1430 }
1431 --index;
1432 }
1433 }
1434 return index;
1435 }
1436
1437
1438
1439
1440
1441 private static int nextNonText( List<?> content, int start )
1442 {
1443 if ( start < 0 )
1444 {
1445 start = 0;
1446 }
1447
1448 int index = start;
1449 int size = content.size();
1450 while ( index < size )
1451 {
1452 Object node = content.get( index );
1453 if ( !( ( node instanceof Text ) || ( node instanceof EntityRef ) ) )
1454 {
1455 return index;
1456 }
1457 index++;
1458 }
1459 return size;
1460 }
1461
1462
1463 private boolean isAllWhitespace( Object obj )
1464 {
1465 String str = null;
1466
1467 if ( obj instanceof String )
1468 {
1469 str = (String) obj;
1470 }
1471 else if ( obj instanceof Text )
1472 {
1473 str = ( (Text) obj ).getText();
1474 }
1475 else if ( obj instanceof EntityRef )
1476 {
1477 return false;
1478 }
1479 else
1480 {
1481 return false;
1482 }
1483
1484 for ( int i = 0; i < str.length(); i++ )
1485 {
1486 if ( !isWhitespace( str.charAt( i ) ) )
1487 {
1488 return false;
1489 }
1490 }
1491 return true;
1492 }
1493
1494
1495 private boolean startsWithWhite( String str )
1496 {
1497 return ( ( str != null ) && ( str.length() > 0 ) && isWhitespace( str.charAt( 0 ) ) );
1498 }
1499
1500
1501 private boolean endsWithWhite( String str )
1502 {
1503 return ( ( str != null ) && ( str.length() > 0 ) && isWhitespace( str.charAt( str.length() - 1 ) ) );
1504 }
1505
1506
1507
1508 private static boolean isWhitespace( char c )
1509 {
1510 return ( c == ' ' || c == '\n' || c == '\t' || c == '\r' );
1511 }
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523 public String escapeAttributeEntities( String str )
1524 {
1525 StringBuilder buffer;
1526 char ch;
1527 String entity;
1528 EscapeStrategy strategy = currentFormat.escapeStrategy;
1529
1530 buffer = null;
1531 for ( int i = 0; i < str.length(); i++ )
1532 {
1533 ch = str.charAt( i );
1534 switch ( ch )
1535 {
1536 case '<':
1537 entity = "<";
1538 break;
1539 case '>':
1540 entity = ">";
1541 break;
1542
1543
1544
1545
1546
1547 case '\"':
1548 entity = """;
1549 break;
1550 case '&':
1551 entity = "&";
1552 break;
1553 case '\r':
1554 entity = "
";
1555 break;
1556 case '\t':
1557 entity = "	";
1558 break;
1559 case '\n':
1560 entity = "
";
1561 break;
1562 default:
1563 if ( strategy.shouldEscape( ch ) )
1564 {
1565 entity = "&#x" + Integer.toHexString( ch ) + ";";
1566 }
1567 else
1568 {
1569 entity = null;
1570 }
1571 break;
1572 }
1573 if ( buffer == null )
1574 {
1575 if ( entity != null )
1576 {
1577
1578
1579 buffer = new StringBuilder( str.length() + 20 );
1580
1581
1582 buffer.append( str.substring( 0, i ) );
1583 buffer.append( entity );
1584 }
1585 }
1586 else
1587 {
1588 if ( entity == null )
1589 {
1590 buffer.append( ch );
1591 }
1592 else
1593 {
1594 buffer.append( entity );
1595 }
1596 }
1597 }
1598
1599
1600
1601
1602 return ( buffer == null ) ? str : buffer.toString();
1603 }
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615 public String escapeElementEntities( String str )
1616 {
1617 if ( escapeOutput == false )
1618 {
1619 return str;
1620 }
1621
1622 StringBuilder buffer;
1623 char ch;
1624 String entity;
1625 EscapeStrategy strategy = currentFormat.escapeStrategy;
1626
1627 buffer = null;
1628 for ( int i = 0; i < str.length(); i++ )
1629 {
1630 ch = str.charAt( i );
1631 switch ( ch )
1632 {
1633 case '<':
1634 entity = "<";
1635 break;
1636 case '>':
1637 entity = ">";
1638 break;
1639 case '&':
1640 entity = "&";
1641 break;
1642 case '\r':
1643 entity = "
";
1644 break;
1645 case '\n':
1646 entity = currentFormat.lineSeparator;
1647 break;
1648 default:
1649 if ( strategy.shouldEscape( ch ) )
1650 {
1651 entity = "&#x" + Integer.toHexString( ch ) + ";";
1652 }
1653 else
1654 {
1655 entity = null;
1656 }
1657 break;
1658 }
1659 if ( buffer == null )
1660 {
1661 if ( entity != null )
1662 {
1663
1664
1665 buffer = new StringBuilder( str.length() + 20 );
1666
1667
1668 buffer.append( str.substring( 0, i ) );
1669 buffer.append( entity );
1670 }
1671 }
1672 else
1673 {
1674 if ( entity == null )
1675 {
1676 buffer.append( ch );
1677 }
1678 else
1679 {
1680 buffer.append( entity );
1681 }
1682 }
1683 }
1684
1685
1686
1687
1688 return ( buffer == null ) ? str : buffer.toString();
1689 }
1690
1691
1692 @Override
1693 public Object clone()
1694 {
1695
1696
1697
1698
1699
1700 try
1701 {
1702 return super.clone();
1703 }
1704 catch ( java.lang.CloneNotSupportedException e )
1705 {
1706
1707
1708
1709
1710 throw new RuntimeException( e.toString() );
1711 }
1712 }
1713
1714
1715
1716
1717
1718
1719
1720 @Override
1721 public String toString()
1722 {
1723 StringBuilder buffer = new StringBuilder();
1724 for ( int i = 0; i < userFormat.lineSeparator.length(); i++ )
1725 {
1726 char ch = userFormat.lineSeparator.charAt( i );
1727 switch ( ch )
1728 {
1729 case '\r':
1730 buffer.append( "\\r" );
1731 break;
1732 case '\n':
1733 buffer.append( "\\n" );
1734 break;
1735 case '\t':
1736 buffer.append( "\\t" );
1737 break;
1738 default:
1739 buffer.append( "[" + ( (int) ch ) + "]" );
1740 break;
1741 }
1742 }
1743
1744 return (
1745 "XMLOutputter[omitDeclaration = " + userFormat.omitDeclaration + ", "
1746 + "encoding = " + userFormat.encoding + ", "
1747 + "omitEncoding = " + userFormat.omitEncoding + ", "
1748 + "indent = '" + userFormat.indent + "'" + ", "
1749 + "expandEmptyElements = " + userFormat.expandEmptyElements + ", "
1750 + "lineSeparator = '" + buffer.toString() + "', "
1751 + "textMode = " + userFormat.mode + "]"
1752 );
1753 }
1754
1755
1756
1757
1758
1759
1760
1761 private NamespaceStack createNamespaceStack()
1762 {
1763
1764 return new NamespaceStack();
1765 }
1766
1767
1768
1769
1770
1771
1772
1773
1774 protected class NamespaceStack
1775 extends org.apache.maven.archetype.common.util.NamespaceStack
1776 {
1777 }
1778
1779
1780
1781 private void printQualifiedName( Writer out, Element e )
1782 throws IOException
1783 {
1784 if ( e.getNamespace().getPrefix().length() == 0 )
1785 {
1786 out.write( e.getName() );
1787 }
1788 else
1789 {
1790 out.write( e.getNamespace().getPrefix() );
1791 out.write( ':' );
1792 out.write( e.getName() );
1793 }
1794 }
1795
1796
1797
1798 private void printQualifiedName( Writer out, Attribute a )
1799 throws IOException
1800 {
1801 String prefix = a.getNamespace().getPrefix();
1802 if ( ( prefix != null ) && ( !prefix.equals( "" ) ) )
1803 {
1804 out.write( prefix );
1805 out.write( ':' );
1806 out.write( a.getName() );
1807 }
1808 else
1809 {
1810 out.write( a.getName() );
1811 }
1812 }
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823 }