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