-
Notifications
You must be signed in to change notification settings - Fork 117
/
SAXBuilder.java
1295 lines (1183 loc) · 41.3 KB
/
SAXBuilder.java
1
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*--
Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JDOM" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact <request_AT_jdom_DOT_org>.
4. Products derived from this software may not be called "JDOM", nor
may "JDOM" appear in their name, without prior written permission
from the JDOM Project Management <request_AT_jdom_DOT_org>.
In addition, we request (but do not require) that you include in the
end-user documentation provided with the redistribution and/or in the
software itself an acknowledgement equivalent to the following:
"This product includes software developed by the
JDOM Project (http://www.jdom.org/)."
Alternatively, the acknowledgment may be graphical using the logos
available at http://www.jdom.org/images/logos.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
This software consists of voluntary contributions made by many
individuals on behalf of the JDOM Project and was originally
created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
on the JDOM Project, please see <http://www.jdom.org/>.
*/
package org.jdom2.input;
import static org.jdom2.JDOMConstants.SAX_FEATURE_EXTERNAL_ENT;
import static org.jdom2.JDOMConstants.SAX_PROPERTY_DECLARATION_HANDLER;
import static org.jdom2.JDOMConstants.SAX_PROPERTY_LEXICAL_HANDLER;
import static org.jdom2.JDOMConstants.SAX_PROPERTY_LEXICAL_HANDLER_ALT;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLFilter;
import org.xml.sax.XMLReader;
import org.jdom2.DefaultJDOMFactory;
import org.jdom2.DocType;
import org.jdom2.Document;
import org.jdom2.EntityRef;
import org.jdom2.JDOMException;
import org.jdom2.JDOMFactory;
import org.jdom2.Verifier;
import org.jdom2.input.sax.BuilderErrorHandler;
import org.jdom2.input.sax.DefaultSAXHandlerFactory;
import org.jdom2.input.sax.SAXBuilderEngine;
import org.jdom2.input.sax.SAXEngine;
import org.jdom2.input.sax.SAXHandler;
import org.jdom2.input.sax.SAXHandlerFactory;
import org.jdom2.input.sax.XMLReaderJDOMFactory;
import org.jdom2.input.sax.XMLReaderSAX2Factory;
import org.jdom2.input.sax.XMLReaders;
/**
* Builds a JDOM Document using a SAX parser.
* <p>
* SAXbuilder uses a third-party SAX parser (chosen by JAXP by default, or you
* can configure it manually) to handle the parsing duties and uses an instance
* of a SAXHandler to listen to the SAX events in order to construct a document
* with JDOM content using a JDOMFactory. Information about SAX can be found at
* <a href="http://www.saxproject.org">http://www.saxproject.org</a>.
* <p>
* For a complete description of how SAXBuilder is used, and how to customise
* the process you should look at the {@link org.jdom2.input.sax} package
* documentation.
* <p>
* JDOM users needing to customise the SAX parsing process have traditionally
* sub-classed this SAXBuilder class. In JDOM2 this should never be necessary.
* Please read the full documentation of this class, {@link SAXHandler},
* {@link SAXHandlerFactory}, {@link JDOMFactory}, and the package documentation
* for {@link org.jdom2.input.sax} before overriding this class. Future versions
* of JDOM2 may make this class 'final'. I you feel you have a good reason to
* subclass SAXBuilder please mention it on <a
* href="http://www.jdom.org/involved/lists.html">jdom-interest</a> mailing list
* so that SAXBuilder can be extended or adapted to handle your use-case.
* <p>
* Neither SAXBuilder nor anything derived from SAXBuilder is thread-safe. You
* must ensure that SAXBuilder is used in a single thread, or that sufficient
* locking is in place to ensure that SAXBuilder is not concurrently accessed.
* See the special note on {@link #buildEngine()}.
* <p>
* Known issues:
* <ul>
* <li>Relative paths for a {@link DocType} or {@link EntityRef} may be
* converted by the SAX parser into absolute paths.
* <li>SAX does not recognise whitespace character content outside the root
* element (nor does JDOM) so any formatting outside the root Element will be
* lost.
* </ul>
*
* @see org.jdom2.input.sax
* @author Jason Hunter
* @author Brett McLaughlin
* @author Dan Schaffer
* @author Philip Nelson
* @author Alex Rosen
* @author Rolf Lear
*/
public class SAXBuilder implements SAXEngine {
/** Default source of SAXHandlers */
private static final SAXHandlerFactory DEFAULTSAXHANDLERFAC =
new DefaultSAXHandlerFactory();
/** Default source of JDOM Content */
private static final JDOMFactory DEFAULTJDOMFAC = new DefaultJDOMFactory();
/*
* ====================================================================
*/
/**
* The XMLReader pillar of SAXBuilder
*/
private XMLReaderJDOMFactory readerfac = null;
/**
* The SAXHandler pillar of SAXBuilder
*/
private SAXHandlerFactory handlerfac = null;
/**
* The JDOMFactory pillar for creating new JDOM objects
*/
private JDOMFactory jdomfac = null;
/*
* ========================================================================
* Configuration settings for SAX parsing.
* ========================================================================
*/
/** User-specified features to be set on the SAX parser */
private final HashMap<String, Boolean> features = new HashMap<String, Boolean>(5);
/** User-specified properties to be set on the SAX parser */
private final HashMap<String, Object> properties = new HashMap<String, Object>(5);
/** ErrorHandler class to use */
private ErrorHandler saxErrorHandler = null;
/** EntityResolver class to use */
private EntityResolver saxEntityResolver = null;
/** DTDHandler class to use */
private DTDHandler saxDTDHandler = null;
/** XMLFilter instance to use */
private XMLFilter saxXMLFilter = null;
/** Whether expansion of entities should occur */
private boolean expand = true;
/** Whether to ignore ignorable whitespace */
private boolean ignoringWhite = false;
/** Whether to ignore all whitespace content */
private boolean ignoringBoundaryWhite = false;
/** Whether parser reuse is allowed. */
private boolean reuseParser = true;
/** The current SAX parser, if parser reuse has been activated. */
private SAXEngine engine = null;
/**
* Creates a new JAXP-based SAXBuilder. The underlying parser will not
* validate.
*
* @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
* JDOMFactory)
* @see XMLReaders#NONVALIDATING
* @see DefaultSAXHandlerFactory
* @see DefaultJDOMFactory
*/
public SAXBuilder() {
this(null, null, null);
}
/**
* Creates a new JAXP-based SAXBuilder. The underlying parser will validate
* (using DTD) or not according to the given parameter. If you want Schema
* validation then use SAXBuilder(XMLReaders.XSDVALIDATOR)
*
* @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
* JDOMFactory)
* @see XMLReaders#NONVALIDATING
* @see XMLReaders#DTDVALIDATING
* @see DefaultSAXHandlerFactory
* @see DefaultJDOMFactory
* @see org.jdom2.input.sax for important details on SAXBuilder
* @param validate
* <code>boolean</code> indicating if DTD validation should occur.
* @deprecated use {@link SAXBuilder#SAXBuilder(XMLReaderJDOMFactory)} with
* either {@link XMLReaders#DTDVALIDATING}
* or {@link XMLReaders#NONVALIDATING}
*/
@Deprecated
public SAXBuilder(final boolean validate) {
this(validate
? XMLReaders.DTDVALIDATING
: XMLReaders.NONVALIDATING,
null, null);
}
/**
* Creates a new SAXBuilder using the specified SAX parser. The underlying
* parser will not validate.
*
* @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
* JDOMFactory)
* @see XMLReaderSAX2Factory
* @see DefaultSAXHandlerFactory
* @see DefaultJDOMFactory
* @see org.jdom2.input.sax for important details on SAXBuilder
* @param saxDriverClass
* <code>String</code> name of SAX Driver to use for parsing.
* @deprecated use {@link SAXBuilder#SAXBuilder(XMLReaderJDOMFactory)} with
* {@link XMLReaderSAX2Factory#XMLReaderSAX2Factory(boolean, String)}
*/
@Deprecated
public SAXBuilder(final String saxDriverClass) {
this(saxDriverClass, false);
}
/**
* Creates a new SAXBuilder using the specified SAX2.0 parser source. The
* underlying parser will validate or not according to the given parameter.
*
* @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
* JDOMFactory)
* @see XMLReaderSAX2Factory
* @see DefaultSAXHandlerFactory
* @see DefaultJDOMFactory
* @see org.jdom2.input.sax for important details on SAXBuilder
* @param saxDriverClass
* <code>String</code> name of SAX Driver to use for parsing.
* @param validate
* <code>boolean</code> indicating if validation should occur.
* @deprecated use {@link SAXBuilder#SAXBuilder(XMLReaderJDOMFactory)} with
* {@link XMLReaderSAX2Factory#XMLReaderSAX2Factory(boolean, String)}
*/
@Deprecated
public SAXBuilder(final String saxDriverClass, final boolean validate) {
this(new XMLReaderSAX2Factory(validate, saxDriverClass), null, null);
}
/**
* Creates a new SAXBuilder with the specified XMLReaderJDOMFactory.
* <p>
*
* @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
* JDOMFactory)
* @see XMLReaderJDOMFactory
* @see XMLReaders#NONVALIDATING
* @see DefaultSAXHandlerFactory
* @see DefaultJDOMFactory
* @see org.jdom2.input.sax for important details on SAXBuilder
* @param readersouce
* the {@link XMLReaderJDOMFactory} that supplies XMLReaders. If the
* value is null then a Non-Validating JAXP-based SAX2.0 parser will
* be used.
*/
public SAXBuilder(final XMLReaderJDOMFactory readersouce) {
this(readersouce, null, null);
}
/**
* Creates a new SAXBuilder. This is the base constructor for all other
* SAXBuilder constructors: they all find a way to create a
* JDOMXMLReaderFactory and then call this constructor with that factory,
* and the {@link DefaultSAXHandlerFactory} and {@link DefaultJDOMFactory}.
* <p>
*
* @see XMLReaderJDOMFactory
* @see XMLReaders#NONVALIDATING
* @see SAXHandlerFactory
* @see DefaultSAXHandlerFactory
* @see JDOMFactory
* @see DefaultJDOMFactory
* @see org.jdom2.input.sax for important details on SAXBuilder
* @param xmlreaderfactory
* a {@link XMLReaderJDOMFactory} that creates XMLReaders. Specify
* null for the default.
* @param handlerfactory
* a {@link SAXHandlerFactory} that creates SAXHandlers Specify null
* for the default.
* @param jdomfactory
* a {@link JDOMFactory} that creates JDOM Content. Specify null for
* the default.
*/
public SAXBuilder(final XMLReaderJDOMFactory xmlreaderfactory, final SAXHandlerFactory handlerfactory,
final JDOMFactory jdomfactory) {
this.readerfac = xmlreaderfactory == null
? XMLReaders.NONVALIDATING
: xmlreaderfactory;
this.handlerfac = handlerfactory == null
? DEFAULTSAXHANDLERFAC
: handlerfactory;
this.jdomfac = jdomfactory == null
? DEFAULTJDOMFAC
: jdomfactory;
}
/**
* Returns the driver class assigned in the constructor, or null if none.
* The driver class is only available if a SAX2 source was specified. This
* method is available for backward-compatibility with JDOM 1.x
*
* @return the driver class assigned in the constructor
* @deprecated as the driver class is only available in limited situations
* and anyway it had to be supplied in a constructor as either a
* direct value or as an {@link XMLReaderSAX2Factory} instance.
*/
@Deprecated
public String getDriverClass() {
if (readerfac instanceof XMLReaderSAX2Factory) {
return ((XMLReaderSAX2Factory) readerfac).getDriverClassName();
}
return null;
}
/**
* Returns the current {@link org.jdom2.JDOMFactory} in use.
*
* @return the factory in use
* @deprecated as it is replaced by {@link #getJDOMFactory()}
*/
@Deprecated
public JDOMFactory getFactory() {
return getJDOMFactory();
}
/**
* Returns the current {@link org.jdom2.JDOMFactory} in use.
*
* @return the factory in use
*/
@Override
public JDOMFactory getJDOMFactory() {
return jdomfac;
}
/**
* This sets a custom JDOMFactory for the builder. Use this to build the
* tree with your own subclasses of the JDOM classes.
*
* @param factory
* <code>JDOMFactory</code> to use
* @deprecated as it is replaced by {@link #setJDOMFactory(JDOMFactory)}
*/
@Deprecated
public void setFactory(final JDOMFactory factory) {
setJDOMFactory(factory);
}
/**
* This sets a custom JDOMFactory for the builder. Use this to build the
* tree with your own subclasses of the JDOM classes.
*
* @param factory
* <code>JDOMFactory</code> to use
*/
public void setJDOMFactory(final JDOMFactory factory) {
this.jdomfac = factory;
engine = null;
}
/**
* Get the current XMLReader factory.
*
* @return the current JDOMXMLReaderFactory
*/
public XMLReaderJDOMFactory getXMLReaderFactory() {
return readerfac;
}
/**
* Set the current XMLReader factory.
*
* @param rfac
* the JDOMXMLReaderFactory to set. A null rfac will indicate the
* default {@link XMLReaders#NONVALIDATING}
*/
public void setXMLReaderFactory(final XMLReaderJDOMFactory rfac) {
readerfac = rfac == null
? XMLReaders.NONVALIDATING
: rfac;
engine = null;
}
/**
* Get the SAXHandlerFactory used to supply SAXHandlers to this SAXBuilder.
*
* @return the current SAXHandlerFactory (never null).
*/
public SAXHandlerFactory getSAXHandlerFactory() {
return handlerfac;
}
/**
* Set the SAXHandlerFactory to be used by this SAXBuilder.
*
* @param factory
* the required SAXHandlerFactory. A null input factory will request
* the {@link DefaultSAXHandlerFactory}.
*/
public void setSAXHandlerFactory(final SAXHandlerFactory factory) {
this.handlerfac = factory == null ? DEFAULTSAXHANDLERFAC : factory;
engine = null;
}
/**
* Returns whether validation is to be performed during the build.
*
* @return whether validation is to be performed during the build
* @deprecated in lieu of {@link #isValidating()}
*/
@Deprecated
public boolean getValidation() {
return isValidating();
}
/**
* Returns whether validation is to be performed during the build.
*
* @return whether validation is to be performed during the build
*/
@Override
public boolean isValidating() {
return readerfac.isValidating();
}
/**
* This sets validation for the builder.
* <p>
* <b>Do Not Use</b>
* <p>
* JDOM2 introduces the concept of XMLReader factories. The XMLReader is
* what determines the type of validation. A simple boolean is not enough to
* indicate what sort of validation is required. The
* {@link #setXMLReaderFactory(XMLReaderJDOMFactory)} method provides a
* means to be more specific about validation.
* <p>
* For backward compatibility this method has been retained, but its use is
* discouraged. It does make some logical choices though. The code is
* equivalent to:
* <p>
*
* <pre>
* setXMLReaderFactory(XMLReaders.DTDVALIDATING)
* </pre>
*
* for true, and
*
* <pre>
* setXMLReaderFactory(XMLReaders.NONVALIDATING)
* </pre>
*
* for false.
*
* @see #setXMLReaderFactory(XMLReaderJDOMFactory)
* @see XMLReaders#NONVALIDATING
* @see XMLReaders#DTDVALIDATING
* @param validate
* <code>boolean</code> indicating whether validation should occur.
* @deprecated use {@link #setXMLReaderFactory(XMLReaderJDOMFactory)}
*/
@Deprecated
public void setValidation(final boolean validate) {
setXMLReaderFactory(validate
? XMLReaders.DTDVALIDATING
: XMLReaders.NONVALIDATING);
}
/**
* Returns the {@link ErrorHandler} assigned, or null if none. When the
* SAXBuilder parses a document it will always have an ErrorHandler but it
* will be an instance of {@link BuilderErrorHandler} unless you specify a
* different ErrorHandler in {@link #setErrorHandler(ErrorHandler)}. In
* other words, a null return value from here indicates a default will be
* used.
*
* @return the ErrorHandler assigned, or null if SAXBuilder will create a
* default ErrorHandler when needed.
*/
@Override
public ErrorHandler getErrorHandler() {
return saxErrorHandler;
}
/**
* This sets custom ErrorHandler for the Builder. Setting a null value will
* indicate SAXBuilder should create a default ErrorHandler when needed.
*
* @param errorHandler
* <code>ErrorHandler</code>
*/
public void setErrorHandler(final ErrorHandler errorHandler) {
saxErrorHandler = errorHandler;
engine = null;
}
/**
* Returns the {@link EntityResolver} assigned, or null if none.
*
* @return the EntityResolver assigned
*/
@Override
public EntityResolver getEntityResolver() {
return saxEntityResolver;
}
/**
* This sets custom EntityResolver for the <code>Builder</code>.
*
* @param entityResolver
* <code>EntityResolver</code>
*/
public void setEntityResolver(final EntityResolver entityResolver) {
saxEntityResolver = entityResolver;
engine = null;
}
/**
* Returns the {@link DTDHandler} assigned, or null if the assigned
* {@link SAXHandler} will be used for DTD SAX events.
*
* @return the DTDHandler assigned
*/
@Override
public DTDHandler getDTDHandler() {
return saxDTDHandler;
}
/**
* This sets custom DTDHandler for the <code>Builder</code>. Setting a null
* value indicates that SAXBuilder should use the assigned SAXHandler for
* DTD processing.
*
* @param dtdHandler
* <code>DTDHandler</code>
*/
public void setDTDHandler(final DTDHandler dtdHandler) {
saxDTDHandler = dtdHandler;
engine = null;
}
/**
* Returns the {@link XMLFilter} used during parsing, or null if none.
*
* @return the XMLFilter used during parsing
*/
public XMLFilter getXMLFilter() {
return saxXMLFilter;
}
/**
* This sets a custom {@link org.xml.sax.XMLFilter} for the builder.
* <p>
* Care should be taken to ensure that the specified xmlFilter is reentrant
* and thread-safe.
* <p>
* SAXBuilder will set this instance as the parent instance for all
* XMLReaders that may be created, and these may (depending on SAXBuilder
* usage) be accessed concurrently. It is the responsibility of the JDOM
* user to ensure that if the XMLFilter is not thread-safe then neither the
* SAXBuilder nor any of it's SAXEngines are accessed concurrently.
*
* @param xmlFilter
* the XMLFilter to use
*/
public void setXMLFilter(final XMLFilter xmlFilter) {
saxXMLFilter = xmlFilter;
engine = null;
}
/**
* Returns whether element content whitespace is to be ignored during the
* build.
*
* @return whether element content whitespace is to be ignored during the
* build
*/
@Override
public boolean getIgnoringElementContentWhitespace() {
return ignoringWhite;
}
/**
* Specifies whether or not the parser should eliminate whitespace in
* element content (sometimes known as "ignorable whitespace") when building
* the document. Only whitespace which is contained within element content
* that has an element only content model will be eliminated (see XML Rec
* 3.2.1). For this setting to take effect requires that validation be
* turned on. The default value of this setting is <code>false</code>.
*
* @param ignoringWhite
* Whether to ignore ignorable whitespace
*/
public void setIgnoringElementContentWhitespace(final boolean ignoringWhite) {
this.ignoringWhite = ignoringWhite;
engine = null;
}
/**
* Returns whether or not the parser will eliminate element content
* containing only whitespace.
*
* @return <code>boolean</code> - whether only whitespace content will be
* ignored during build.
* @see #setIgnoringBoundaryWhitespace
*/
@Override
public boolean getIgnoringBoundaryWhitespace() {
return ignoringBoundaryWhite;
}
/**
* Specifies whether or not the parser should elminate boundary whitespace,
* a term that indicates whitespace-only text between element tags. This
* feature is a lot like
* {@link #setIgnoringElementContentWhitespace(boolean)} but this feature is
* more aggressive and doesn't require validation be turned on. The
* {@link #setIgnoringElementContentWhitespace(boolean)} call impacts the
* SAX parse process while this method impacts the JDOM build process, so it
* can be beneficial to turn both on for efficiency. For implementation
* efficiency, this method actually removes all whitespace-only text()
* nodes. That can, in some cases (like between an element tag and a
* comment) include whitespace that isn't just boundary whitespace. The
* default is <code>false</code>.
*
* @param ignoringBoundaryWhite
* Whether to ignore whitespace-only text nodes
*/
public void setIgnoringBoundaryWhitespace(final boolean ignoringBoundaryWhite) {
this.ignoringBoundaryWhite = ignoringBoundaryWhite;
engine = null;
}
/**
* Returns whether or not entities are being expanded into normal text
* content.
*
* @return whether entities are being expanded
*/
@Override
public boolean getExpandEntities() {
return expand;
}
/**
* <p>
* This sets whether or not to expand entities for the builder. A true means
* to expand entities as normal content. A false means to leave entities
* unexpanded as <code>EntityRef</code> objects. The default is true.
* </p>
* <p>
* When this setting is false, the internal DTD subset is retained; when
* this setting is true, the internal DTD subset is not retained.
* </p>
* <p>
* Note that Xerces (at least up to 1.4.4) has a bug where entities in
* attribute values will be incorrectly reported if this flag is turned off,
* resulting in entities appearing within element content. When turning
* entity expansion off either avoid entities in attribute values, or use
* another parser like Crimson.
* http://nagoya.apache.org/bugzilla/show_bug.cgi?id=6111
* </p>
*
* @param expand
* <code>boolean</code> indicating whether entity expansion should
* occur.
*/
public void setExpandEntities(final boolean expand) {
this.expand = expand;
engine = null;
}
/**
* Returns whether the contained SAX parser instance is reused across
* multiple parses. The default is true.
*
* @return whether the contained SAX parser instance is reused across
* multiple parses
*/
public boolean getReuseParser() {
return reuseParser;
}
/**
* Specifies whether this builder will reuse the same SAX parser when
* performing subsequent parses or allocate a new parser for each parse. The
* default value of this setting is <code>true</code> (parser reuse).
* <p>
* <strong>Note</strong>: SAX parser instances are not thread safe (they are
* not even reentrant), and nor are SAXBuilder instances. Setting parser
* reuse does not imply the parser is thread-safe.
* </p>
*
* @param reuseParser
* Whether to reuse the SAX parser.
*/
public void setReuseParser(final boolean reuseParser) {
this.reuseParser = reuseParser;
if (!reuseParser) {
engine = null;
}
}
/**
* Specifies whether this builder will do fast reconfiguration of the
* underlying SAX parser when reuseParser is true. This improves performance
* in cases where SAXBuilders are reused and lots of small documents are
* frequently parsed. This avoids attempting to set features on the SAX
* parser each time build() is called which result in
* SaxNotRecognizedExceptions. This should ONLY be set for builders where
* this specific case is an issue. The default value of this setting is
* <code>false</code> (no fast reconfiguration). If reuseParser is false,
* calling this has no effect.
*
* @param fastReconfigure
* Whether to do a fast reconfiguration of the parser
* @deprecated All reused Parsers are now fast-reconfigured. No need to set
* it.
*/
@Deprecated
public void setFastReconfigure(final boolean fastReconfigure) {
// do nothing
}
/**
* This sets a feature on the SAX parser. See the SAX documentation for
* more information. </p>
* <p>
* NOTE: SAXBuilder requires that some particular features of the SAX parser
* be set up in certain ways for it to work properly. The list of such
* features may change in the future. Therefore, the use of this method may
* cause parsing to break, and even if it doesn't break anything today it
* might break parsing in a future JDOM version, because what JDOM parsers
* require may change over time. Use with caution.
* </p>
* JDOM uses {@link XMLReaderJDOMFactory} instances to provide XMLReader
* instances. If you require special configuration on your XMLReader you
* should consider extending or implementing an XMLReaderJDOMFactory in the
* {@link org.jdom2.input.sax} package.
*
* @param name
* The feature name, which is a fully-qualified URI.
* @param value
* The requested state of the feature (true or false).
*/
public void setFeature(final String name, final boolean value) {
// Save the specified feature for later.
features.put(name, value ? Boolean.TRUE : Boolean.FALSE);
engine = null;
}
/**
* This sets a property on the SAX parser. See the SAX documentation for
* more information.
* <p>
* NOTE: SAXBuilder requires that some particular properties of the SAX
* parser be set up in certain ways for it to work properly. The list of
* such properties may change in the future. Therefore, the use of this
* method may cause parsing to break, and even if it doesn't break anything
* today it might break parsing in a future JDOM version, because what JDOM
* parsers require may change over time. Use with caution.
* </p>
* JDOM uses {@link XMLReaderJDOMFactory} instances to provide XMLReader
* instances. If you require special configuration on your XMLReader you
* should consider extending or implementing an XMLReaderJDOMFactory in the
* {@link org.jdom2.input.sax} package.
*
* @param name
* The property name, which is a fully-qualified URI.
* @param value
* The requested value for the property.
*/
public void setProperty(final String name, final Object value) {
// Save the specified property for later.
properties.put(name, value);
engine = null;
}
/**
* This method builds a new and reusable {@link SAXEngine}.
* Each time this method is called a new instance of a SAXEngine will be
* returned.
* <p>
* This method is used internally by the various SAXBuilder.build(*) methods
* (if any configuration has changed) but can also be used as a mechanism
* for creating SAXEngines to be used in parsing pools or other optimised
* structures.
*
* @return a {@link SAXEngine} representing the current state of the
* current SAXBuilder settings.
* @throws JDOMException
* if there is any problem initialising the engine.
*/
public SAXEngine buildEngine() throws JDOMException {
// Create and configure the content handler.
final SAXHandler contentHandler = handlerfac.createSAXHandler(jdomfac);
contentHandler.setExpandEntities(expand);
contentHandler.setIgnoringElementContentWhitespace(ignoringWhite);
contentHandler.setIgnoringBoundaryWhitespace(ignoringBoundaryWhite);
final XMLReader parser = createParser();
// Configure parser
configureParser(parser, contentHandler);
final boolean valid = readerfac.isValidating();
return new SAXBuilderEngine(parser, contentHandler, valid);
}
/**
* Allow overriding classes access to the Parser before it is used in a
* SAXBuilderEngine.
*
* @return a XMLReader parser.
* @throws JDOMException
* if there is a problem
*/
protected XMLReader createParser() throws JDOMException {
XMLReader parser = readerfac.createXMLReader();
// Install optional filter
if (saxXMLFilter != null) {
// Connect filter chain to parser
XMLFilter root = saxXMLFilter;
while (root.getParent() instanceof XMLFilter) {
root = (XMLFilter) root.getParent();
}
root.setParent(parser);
// Read from filter
parser = saxXMLFilter;
}
return parser;
}
/**
* This method retrieves (or builds) a SAXBuilderEngine that represents the
* current SAXBuilder state.
*
* @return a {@link SAXBuilderEngine} representing the current state of the
* current SAXBuilder settings.
* @throws JDOMException
* if there is any problem initializing the engine.
*/
private SAXEngine getEngine() throws JDOMException {
if (engine != null) {
return engine;
}
engine = buildEngine();
return engine;
}
/**
* This configures the XMLReader to be used for reading the XML document.
* <p>
* The default implementation sets various options on the given XMLReader,
* such as validation, DTD resolution, entity handlers, etc., according to
* the options that were set (e.g. via <code>setEntityResolver</code>) and
* set various SAX properties and features that are required for JDOM
* internals. These features may change in future releases, so change this
* behavior at your own risk.
* </p>
*
* @param parser
* the XMLReader to configure.
* @param contentHandler
* The SAXHandler to use for the XMLReader
* @throws JDOMException
* if configuration fails.
*/
protected void configureParser(final XMLReader parser, final SAXHandler contentHandler)
throws JDOMException {
// Setup SAX handlers.
parser.setContentHandler(contentHandler);
if (saxEntityResolver != null) {
parser.setEntityResolver(saxEntityResolver);
}
if (saxDTDHandler != null) {
parser.setDTDHandler(saxDTDHandler);
} else {
parser.setDTDHandler(contentHandler);
}
if (saxErrorHandler != null) {
parser.setErrorHandler(saxErrorHandler);
} else {
parser.setErrorHandler(new BuilderErrorHandler());
}
boolean success = false;
try {
parser.setProperty(SAX_PROPERTY_LEXICAL_HANDLER,
contentHandler);
success = true;
} catch (final SAXNotSupportedException e) {
// No lexical reporting available
} catch (final SAXNotRecognizedException e) {
// No lexical reporting available
}
// Some parsers use alternate property for lexical handling (grr...)
if (!success) {
try {
parser.setProperty(SAX_PROPERTY_LEXICAL_HANDLER_ALT,
contentHandler);
success = true;
} catch (final SAXNotSupportedException e) {
// No lexical reporting available
} catch (final SAXNotRecognizedException e) {
// No lexical reporting available
}
}
// Set any user-specified features on the parser.
for (final Map.Entry<String, Boolean> me : features.entrySet()) {
internalSetFeature(parser, me.getKey(), me.getValue().booleanValue(), me.getKey());
}
// Set any user-specified properties on the parser.
for (final Map.Entry<String, Object> me : properties.entrySet()) {
internalSetProperty(parser, me.getKey(), me.getValue(), me.getKey());
}
// Set entity expansion
// Note SAXHandler can work regardless of how this is set, but when
// entity expansion it's worth it to try to tell the parser not to
// even bother with external general entities.
// Apparently no parsers yet support this feature.
// XXX It might make sense to setEntityResolver() with a resolver
// that simply ignores external general entities
try {
if (parser.getFeature(SAX_FEATURE_EXTERNAL_ENT) != expand) {
parser.setFeature(SAX_FEATURE_EXTERNAL_ENT, expand);
}
} catch (final SAXException e) { /* Ignore... */
}
// Try setting the DeclHandler if entity expansion is off
if (!expand) {
try {